I try to find all documents from collection if it _id is not in array.
This is my code:
warehouses.find(query, items).toArray(function (error, docs) {
if (error) {
error(error);
return;
}
if (docs) {
var material = db.collection('material');
material.find({$nin: {'_id': docs[0].items}}, function (e, items) {
if (error) {
error(error);
return;
}
success(items);
});
}
});
in material.find line, currentItems have two ObjectsID, but the return of find is empty..What is wrong?
It is related to event-loop feature of nodejs. Each callback function is executed parallelly. So, while the line that starts with"material.find" started to be executed, probably
function (item, index) {
currentItems[index] = item._id;
}
is still being executed. This is why you get an empty result. To achieve your goal, you should done all work in only one callback function. Follow these steps:
select only ids in the first query(populate currentItems variable in the query). so, you can remove doc.items.foreach....
Then call the the function material.find.... inside callback function of the query.
Related
const collect = [];
req.body.product.forEach(function(entry) {
mongoClient.connect(databaseServerUrl, function(err, db) {
let testCollection = db.collection('Tests');
testCollection.find({Product: entry}).toArray((err, docs) => {
let waiting = docs.length;
docs.forEach(function (doc) {
collect.push(doc);
finish();
});
function finish() {
waiting--;
if (waiting === 0) {
res.send(collect);
}
}
});
db.close();
});
});
this is only getting back the first set. If I have two nodes in my array of req.body.product for example. I am only getting back the first set. But I need to get back everything not just from one Collection.
Rather than performing two queries and combining the results into one array, I suggest performing a single query that gets all of the results, which would look something like this:
mongoClient.connect(databaseServerUrl, function(err, db) {
const query = { $or: req.body.product.map(Product => ({ Product })) };
db.collection('Tests').find(query).toArray((err, docs) => {
// ...handle `err` here...
res.send(docs);
db.close();
});
});
Note that I haven't tested this since I don't have a MongoDB database in front of me.
your mongoClient.connect() is asyncronous but your loop just execute without waiting for the callback.
Try async forEach loop: enter link description here
This should solve your problem
I need to edit a Game object by adding a User object to it. This is done by the mongoose query findById. This query works. But however, when I want to add the modified game to the resulting array, something goes wrong. The 'console.log(game);' returns the right output, but the 'console.log(result);' is always empty. What is going wrong? Is it something with inner functions?
var result = [];
games.forEach(function(game){
User.findById(game.user1_id, function(err, user){
if(err)
console.log(err);
game.user1 = user;
result.push(game);
console.log(game);
});
});
console.log(result);
You have run into a class callback problem. When you call forEach on games the code will actually continue outside the callback and the result will therefore be the value you first assigned to it, which is []. This is due to the code being evaluated asynchronous.
Solve this by moving your code into a function with a callback that is called when the loop is done, like this:
var utils = require('restberry-utils');
var getResult = function(next) {
var result = [];
utils.forEachAndDone(games, function(game, iter) {
User.findById(game.user1_id, function(err, user) {
if (err) console.log(err);
game.user1 = user;
result.push(game);
iter();
});
}, function() {
next(result);
});
};
getResult(function(result) {
console.log(result);
});
Notice I've imported the restberry-utils package and used the forEachAndDone method. This method will loop through the objects but won't continue unless you call the iter method. When it has looped through all the objects, the last callback is called which is where I'm returning the result.
Hope this makes sense.
I know this will be something small I'm missing, but would appreciate the help.
Here is my test script (node.js)
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/myTestDB',
function (err, db) {
if (err)
debugger;
else {
db.collection('test', function (err, collection) {
collection.save({ name: "danny" }, function () { debugger;});
collection.find(function (err, results) {
if(results.items.length == 0){
///======> always = 0 !!!! WHY?!!!!
debugger;
}
});
});
}
db.close();
});
feel free to start your answer with "duh!"
UPDATE: you also need to move your db.close(); call inside the find callback or you're closing the connection before you're done with it.
In your example, results is a cursor, not an array of docs, so you need to call toArray on it to iterate over the cursor and get the array of docs. But you also need to put your find call inside the save callback. Otherwise the find is executing before the save has completed.
So something like this instead:
collection.save({ name: "danny" }, function () {
collection.find().toArray(function (err, results) {
// results contains the array of docs
// Now you can close the connection.
db.close();
});
});
In a node.js server, using the mongodb native driver, I want to retrieve records from a cursor and then output them as JSON. I have this (simplified)
var ans = {ids: []};
cursor.each(function(err, doc) {
if (doc) {
ans.ids.push(doc.tag);
}
});
cursor.count(function(err, result) {
ans.count = result;
res.send(JSON.stringify(ans));
});
and the result is something like {ids:[], count: 3}. In other words the query appears to run without returning any records. I assume that this is because the data's already been sent before the cursor.each callbacks have run. How do I re-structure this to make sure the sending happens after the iterating?
I have found the answer. The example for cursor.each says "If the item is null then the cursor is exhausted/empty and closed", so: (error handling omitted)
var ans = {ids: []};
cursor.each(function(err, doc) {
if (doc) {
ans.ids.push(doc.tag);
}
else {
cursor.count(function(err, result) {
ans.count = result;
res.send(JSON.stringify(ans));
});
}
});
I'm starting to learn node.js, and to aggregate multiple rss feeds in a single one, I'm fectching the feeds and then recreate a unique feed from the data I fecthed.
So, in order to handle multiple http requests asynchronously I use https://github.com/caolan/async#forEach which does the job.
But I can't figure how to return a value (the rss xml feed in my case).
Here is my code :
function aggregate(topic) {
async.forEach(topic.feeds,
function(item, callback) {
parseAndProcessFeed(item, callback);
},
function(err) {
// sort items by date
items.sort(function(a, b) {
return (Date.parse(b.date) - Date.parse(a.name));
});
var rssFeed = createAggregatedFeed();
console.log(rssFeed);
return rssFeed;
}
);
}
with console.log(rssFeed) I can see the rss feed, so I think I'm missing something obvious.
How can I return the rssFeed value?
Some help to get me back on seat would be great, thanks!
Xavier
You can't return value from asyncronious function. You need pass it into callback function. Like this:
function aggregate(topic, callback) {
async.forEach(topic.feeds,
function(item, callback) {
parseAndProcessFeed(item, callback);
},
function(err) {
// sort items by date
items.sort(function(a, b) {
return (Date.parse(b.date) - Date.parse(a.name));
});
var rssFeed = createAggregatedFeed();
callback(err, rssFeed);
}
);
}
aggregate(someTopic, function(err, result) {
// here is result of aggregate
});