Reputation: 1151
I need help pulling out objects of objects from my database through a get request, so I can display all of it on my web page, but this test I ran already failed, debugging it, it just runs forever and the JSON is never received. I think my logic might be messed up somewhere. I'm not sure if I should use async for this, it does look like callback hell, and now thinking about it I probably should, but I don't know if thinking in optimization if this is a decent way, I usually start from the worst case, and with the attempt I ran below what I was aiming for was around O(N) since there are N total documents and I'm just traversing down a recursion tree, with some additional queries for finding the initial documents and what not so, N+X (where x is a additional amount of queries < N). But I feel as if I'm missing out on something conceptually as if there might be a better way.
I have a schema, something like this
Doc {
title : string,
author : string,
subDoc : [{type: mongoose.Schema.Types.ObjectId, ref : 'Doc'}]
}
So there are documents I generate and everytime I generate these documents I have subdocuments that can exist for these documents, and even those subdocuments can have subdocuments. Then we end up with some tree-like structure. However I wan't to display the Document > then its sub_doc1 > all of its subdocs... etc > its sub doc2 > all of its sub doc..> etc..
However I don't know if what I'm thinking is efficient and if it is worth even doing with this many queries.
app.get('/docs/:doc/subDocTree', function(req, res) {
var array = [];
var id = req.params.doc;
var num_proc = 0;
console.log(id);
Doc.findById(id, function(err, doc) {
console.log(doc);
for (var x = 0; x < doc.subDoc.length; x++) {
Doc.findById(form.subDoc[x], function(err, subDoc) {
populate(subDoc);
});
}
num_proc = num_proc + 1;
if (num_proc == Doc.subDoc.length) {
res.json(array);
array.length = 0;
}
});
});
function populate(docs) {
var num_proc = 0;
Form.findById(docss, function(err, doc) {
if (doc.subform.length != 0) {
//console.log(form);
var total = doc.subDoc.length;
for (var i = 0; i < total; i++) {
array.push(doc.subDoc[x]);
num_proc = num_proc + 1;
populate(subDoc[x]);
}
}
});
}
I thought that searching for the document first, then searching for all of its subdocuments, then recursively checking with the populate method for any subdocs of subdocs would work. However I never end up recieving the JSON, and through debugging with print statements/console.logs, I still couldn't figure out where I went wrong.
Upvotes: 1
Views: 3144
Reputation: 26
Your code is async which doesn't work with for loop.
for (var x = 0; x < doc.subDoc.length; x++) {
Doc.findById(form.subDoc[x], function(err, subDoc) {
populate(subDoc);
});
}
num_proc = num_proc + 1;
if (num_proc == Doc.subDoc.length) {
res.json(array);
array.length = 0;
}
res.json(array)
will be executed before populate(subDoc)
You should either use async library or promises to handle this.
Also mongoose already has a built in method to populate sub documents.
****Update****
It seems you'll benefit from this module: deep-populate
Combined with promises here's how I'd re-write your code:
First, I'd promisify the mongoose
object (using bluebird)
// Promisification
var Promise = require('bluebird');
var mongoose = require('mongoose');
Promise.promisifyAll(mongoose);
Then in the schema definition I'd use that deep-populate plugin
var deepPopulate = require('mongoose-deep-populate');
Doc.plugin(deepPopulate, options);
So now your route would look like this:
app.get('/docs/:doc/subDocTree', function(req, res) {
var id = req.params.doc;
Doc.findById(id).deepPopulate('subDoc').execAsync()
.then(function(doc){
res.json(doc.subDoc);
}).catch(function(err){
// handle error
res.send('Something went wrong...' + err.message);
});
});
Upvotes: 1