Reputation: 189
I am trying to implement following MongoDB query in NodeJS
db.tvseries.find({}).map(function(doc){
var userHasSubscribed = false;
doc.followers && doc.followers.forEach(function(follower) {
if(follower.$id == "abc") {
userHasSubscribed = true;
}
});
var followers = doc.followers && doc.followers.map(function(follower) {
var followerObj;
db[follower.$ref].find({
"_id" : follower.$id
}).map(function(userObj) {
followerObj = userObj;
});
return followerObj;
});
return {
"id": doc.name,
"userHasSubscribed": userHasSubscribed,
"followers": followers || []
};
})
Following is the db
users collection
{
"id": ObjectId("abc"),
"name": "abc_name"
},
{
"id": ObjectId("def"),
"name": "def_name"
},
{
"id": ObjectId("ijk"),
"name": "ijk_name"
}
tvseries collection
{
"id": ObjectId("123"),
"name": "123_name",
"followers": [
{
"$ref": "users",
"$id": ObjectId("abc"),
},
{
"$ref": "users",
"$id": ObjectId("def"),
}
]
},
{
"id": ObjectId("456"),
"name": "456_name",
"followers": [
{
"$ref": "users",
"$id": ObjectId("ijk"),
},
]
},
{
"id": ObjectId("789"),
"name": "789_name"
}
I am not able to figure out how to execute the above MongoDB query in NodeJS with the help of node-mongodb-native plugin.
I tried the below code but then I get TypeError: undefined is not a function at .map
var collection = db.collection('users');
collection.find({}).map(function(doc) {
console.log(doc);
});
How to execute .map function in NodeJS?
Thanks in advance
Upvotes: 2
Views: 7548
Reputation: 4263
map
returns a cursor, toArray
returns a Promise
that will execute a cursor and return it's results. That may be an array of the original query find
, limit
etc. or a promise of an array of those result piped through a function.
This is typically useful when you want to take the documents of the cursor and process that (maybe fetch something else) while the cursor is still fetching documents, as opposed to waiting until they have all been fetched to node memory
Consider the example
let foos = await db.collection("foos")
.find()
.project({
barId: 1
})
.toArray() // returns a Promise<{barId: ObjectId}[]>
// we now have all foos into memory, time to get bars
let bars = await Promise.all(foos.map(doc => db
.collection("bars")
.findOne({
_id: doc.barId
})))
this is roughly equivalent to
bars = await db.collection("foos")
.find()
.project({
barId: 1
})
.toArray() // returns a Promise<{barId: ObjectId}[]>
.then(docs => docs
.map(doc => db
.collection("bars")
.findOne({
_id: doc.barId
})))
using map
you can perform the operation asynchrounsly and (hopefully) more efficiently
bars = await db.collection("foos")
.find()
.project({
barId: 1
})
.map(doc => db
.collection("bars")
.findOne({
_id: doc.barId
}))
.toArray()
.then(barPromises => Promise.all(barPromises)) // Promise<Bar[]>
The main point is that map
is simply a function to be applied to the results fetched by the cursor. That function won't get executed until you turn it into a Promise
, using either forEach
or more sensibly, map
Upvotes: 0
Reputation: 4439
To echo @bamse's anwer, I got it working with .toArray()
. Here is an async example:
async function getWordArray (query) {
const client = await MongoClient.connect(url)
const collection = client.db('personal').collection('wordBank')
const data = await collection.find(query).map(doc => doc.word).toArray()
return data
}
Then I use it in my Express route like this:
app.get('/search/:fragment', asyncMiddleware(async (req, res, next) => {
const result = await getWordArray({word: 'boat'})
res.json(result)
}))
Finally, if you need a guide to async/await middleware in NodeJS, here is a guide: https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016
Upvotes: 3
Reputation: 4383
I struggled with this for some time. I found that by adding .toArray()
after the map
function works.
You could even skip map
and only add .toArray()
to get all the documents fields.
const accounts = await _db
.collection('accounts')
.find()
.map(v => v._id) // leaving this out gets you all the fields
.toArray();
console.log(accounts); // [{_id: xxx}, {_id: xxx} ...]
Please take note that in order for map
to work the function used must return something - your example only console.log
s without returning a value.
The forEach
solution works but I really wanted map
to work.
Upvotes: 8
Reputation: 1061
I know that I'm pretty late but I've arrived here by searching on Google about the same problem. Finally, I wasn't able to use map
function to do it, but using forEach
did the trick.
An example using ES6 and StandardJS.
let ids = []
let PublicationId = ObjectID(id)
feeds_collection
.find({PublicationId})
.project({ _id: 1 })
.forEach((feed) => {
ids.push(feed._id)
}, () => done(ids))
Upvotes: 5