I've been poking around this for several hours... Thanks for any help.
I have a "Users" collection, each user has an _id
and some names (Username
, FirstName
, LastName
).
I also have a "Group" collection, each group has Members
, which is an array of users' _id
.
At first I wanted a simple function that receives an array of ids and turns it into an array of strings in a nice format: FirstName + " " + LastName + " (" + Username + ")"
. So I made a simple for
for that:
var ans = [];
for (i=0; i<arrOfIds.length; i++) {
users.find({"_id": ObjectID(arrOfIds[i])}, function(err, result){
ans.push = result.FirstName + result.LastName + "(" + result.Username + ")";
});
}
But since mongo is async that didn't work. After some reading, I installed async which I thought will solve my problem. I tried just async, async.whilst, async.times and even tried to hack something with async.waterfall - but nothing worked - pretty much all ended the same way: the array was passed before the strings were push to it.
Maybe my approach to this task is wrong?
I've been poking around this for several hours... Thanks for any help.
I have a "Users" collection, each user has an _id
and some names (Username
, FirstName
, LastName
).
I also have a "Group" collection, each group has Members
, which is an array of users' _id
.
At first I wanted a simple function that receives an array of ids and turns it into an array of strings in a nice format: FirstName + " " + LastName + " (" + Username + ")"
. So I made a simple for
for that:
var ans = [];
for (i=0; i<arrOfIds.length; i++) {
users.find({"_id": ObjectID(arrOfIds[i])}, function(err, result){
ans.push = result.FirstName + result.LastName + "(" + result.Username + ")";
});
}
But since mongo is async that didn't work. After some reading, I installed async which I thought will solve my problem. I tried just async, async.whilst, async.times and even tried to hack something with async.waterfall - but nothing worked - pretty much all ended the same way: the array was passed before the strings were push to it.
Maybe my approach to this task is wrong?
Share Improve this question asked Dec 30, 2015 at 18:12 Yogev LevyYogev Levy 3353 silver badges16 bronze badges2 Answers
Reset to default 5If you already have an array of user ids then it would be best if you convert that string array to an array of ObjectIds using the map()
method and then in the find()
query use the $in
operator which selects the documents where the value of a field equals any value in the specified array.
You would need to call the toArray()
method on the find()
cursor so that you can get the results in an array, further manipulate the array to return the desired result, something like the following:
var MongoClient = require('mongodb').MongoClient,
ObjectID = require('mongodb').ObjectID;
MongoClient.connect('mongodb://localhost:27017/test', function(err, db) {
// Get users collection
var Users = db.collection('users');
// Retrieve all the documents in the collection
Users.find({ "_id": { "$in": arrOfIds.map(ObjectID) } })
.toArray().then(function(users) {
// Create array of names
var ans = users.map(function (u){
return u.FirstName + " " + u.LastName + " (" + u.Username + ")";
});
// Do something with the result
console.log(ans);
db.close();
});
});
Another approach is taking the aggregate route in which you can use the $group
pipeline step to create the desired array with $push
and $concat
operators.
Consider running the following aggregate operation:
var MongoClient = require('mongodb').MongoClient,
ObjectID = require('mongodb').ObjectID;
MongoClient.connect('mongodb://localhost:27017/test', function(err, db) {
// Get users collection
var Users = db.collection('users');
// Retrieve all the documents in the collection
Users.aggregate([
{ "$match": { "_id": { "$in": arrOfIds.map(ObjectID) } } },
{ "$group": {
"_id": null,
"users": {
"$push": {
"$concat": ["$FirstName", " ", "$LastName", " (", "$Username", ")"]
}
}
} }
]).toArray().then(results => {
const ans = results[0].users;
// Do something with the result
console.log(ans);
db.close();
});
});
You can use the $in
operator to find multiple users with a single query. This is both better for performance and less hassle with asynchronicity.
// Convert the list of ids to mongo object ids
var objectIds = arrOfIds.map(function(item) {
return ObjectId(item);
});
// Use the $in operator to find multiple users by id
users.find({ "_id": { $in: objectIds } }, function(err, result) {
// result is now a list of users
});