I have a user collection. In that collection each user when they enter a prize will have the prize id stored on their profile. Export of a typical user document below
{
"_id" : ObjectId("5aacff47c67f99103bcbf693"),
"firstName" : "Test",
"lastName" : "Test",
"password" : "$2a$10$mJjzPFWuYPmK8A07nc284O8g9SStFpuaVzfyWOZgaCmVaomIxk5qO",
"email" : "test1@test.com",
"points" : NumberInt(6),
"prizes" : [
ObjectId("5aafd1673a5b2cb294b69620"),
ObjectId("5aafd1673a5b2cb294b69620"),
ObjectId("5aafd1673a5b2cb294b69620"),
ObjectId("5aafd1673a5b2cb294b69620"),
ObjectId("5aafd1673a5b2cb294b69620"),
ObjectId("5ab28ca784aa6390aa5a1dba")
],
"messages" : [
],
"__v" : NumberInt(26)
}
I wrote a api call that when a user lands on their account page, it finds the user and returns their prize entires (array of prizes). I then want to use these to query the DB to find the title/content of each entry so it can be displayed on the front end.
I've done this two ways
var prizes = user.prizes
//mongo
ids = prizes.map(function(el) { return mongoose.Types.ObjectId(el) })
Prize.aggregate([
{ $match: { "_id": { "$in": ids } } }
], function(err, ret){
if (err) {
return res.status(500).json({
title: 'An error occurred',
error: err
});
}
console.log(ret)
}
)
or
Prize.find( { _id: prizes }, { title: 1, content: 1 }, function(err, ret){
if (err) {
return res.status(500).json({
title: 'An error occurred',
error: err
});
}
console.log(ret)
})
Now the difficult part, both of these operations only return unique documents, (2) and not the 6 I wanted.
I wanted to find for every entry id then return that prize id's title and content , without caring if unique or not or have a count in response, so giving my user above it would return
{1x unique doc count 4} {1x unique doc, count 1}
or return 6 responses.
Even when I used the .count(), it only counted 2. I know I must be going about this the wrong way, as mongo is correct in that i'm asking it to find the documents matching the id's I pass it and it finds the 2 matching id's and serves them up.
Am i almost breaking it's functionality by asking it to do something different? Other options? Wrap it up in a for each in node and query each id manually and push to an array?
Get the prizes for specific user.
$unwind
and $group
to count no of prizes followed by $lookup
to get prizes fields in 3.4.
User.aggregate([
{"$match":{"_id":mongoose.Types.ObjectId(userid)}},
{"$unwind":"$prizes"},
{"$group":{"_id":"$prizes","count":{"$sum":1}}},
{"$lookup":{
"from":"prizes", // name of the prize collection
"localField":"_id",
"foreignField":"_id",
"as":"prizes"
}},
{"$addFields":{"prizes":{"$arrayElemAt":["$prizes",0]}}}
])
Get both the user and prizes.
Use $lookup
followed by $map
to keep the fields from lookup and use $filter
with $size
to count the no of prizes for each id in 3.4.
Something like
User.aggregate([
{"$match":{"_id":mongoose.Types.ObjectId(userid)}},
{"$lookup":{
"from":"prizes", // name of the prize collection
"localField":"prizes",
"foreignField":"_id",
"as":"prizeinfo"
}},
{"$addFields":{
"prizeinfo":{
"$map":{
"input":"$prizeinfo",
"as":"pi",
"in":{
"title":"$$pi.title",
"content":"$$pi.content",
"count":{
"$size":{
"$filter":{
"input":"$prizes",
"as":"p",
"cond":{"$eq":["$$pi._id","$$p"]}
}
}
}
}
}
}
}}
])
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.