Reputation: 135
Here is the structure of the document.
{
"_id" : ObjectId("5548b2b79b9567341c77d352"),
"messages" : [
{
"subject" : "fresh subject ",
"from" : ObjectId("5534b2992a104ed914435c31"),
"_id" : ObjectId("5548b5dab9279faf1c1b8688"),
"created" : ISODate("2015-05-05T12:21:46.261Z"),
"read" : true,
"message" : "fresh message ",
"participants" : [
ObjectId("5534b2992a104ed914435c31"), //logged in user
ObjectId("5530af38576214dd3553331c")
]
},
{
"subject" : " subjet",
"from" : ObjectId("5530af38576214dd3553331c"),
"_id" : ObjectId("5548b608b9279faf1c1b8689"),
"created" : ISODate("2015-05-05T12:22:32.809Z"),
"read" : true,
"message" : "is fresh?",
"participants" : [
ObjectId("5530af38576214dd3553331c")
]
}
],
"participants" : [
ObjectId("5534b2992a104ed914435c31"),
ObjectId("5530af38576214dd3553331c")
],
"__v" : 2
}
There are several objects inside the messages array of a perticular object. I want to get the objects inside the messages array only if the participants array of that object contains logged in user.
I have object Id of the document (5548b2b79b9567341c77d352) and I have the logged in user id (5534b2992a104ed914435c31). How to do the same in mongoose ?
Upvotes: 4
Views: 1043
Reputation: 14552
Another solution apart from the aggregation framework is to use the $elemMatch projection operator.
For example:
var id = '5548b2b79b9567341c77d352';
var loggedInUserId = '5534b2992a104ed914435c31';
var projection = {
participants: 1,
messages: {
$elemMatch: { participants: new ObjectId(loggedInUserId) }
}
};
Model.findById(id, projection, function(err, result) {
console.log(result);
});
This will output:
{ _id: 5548b2b79b9567341c77d352,
participants: [ 5534b2992a104ed914435c31, 5530af38576214dd3553331c ],
messages:
[ { participants: [Object],
message: 'fresh message ',
read: true,
created: Tue May 05 2015 09:21:46 GMT-0300 (BRT),
_id: 5548b5dab9279faf1c1b8688,
from: 5534b2992a104ed914435c31,
subject: 'fresh subject ' } ] }
Upvotes: 1
Reputation: 191729
You can use the Aggregation Framework to $unwind
the subdocument arrays (splits them into their own documents that you can match against. The query I would use:
.aggregate([
{$unwind: "$messages"},
{$match:
{"messages.participants": ObjectId("5534b2992a104ed914435c31")}
}
])
This will return a separate message
document in the result set for each message
subdocument that matches that participant.
Using Mongoose constructs this would look something like:
Conversation
.aggregate({$unwind: "messages"})
.match({
"messages.participants": mongoose.Types.ObjectId("5534b2992a104ed914435c31")
})
.exec(cb);
The first $match
is not strictly necessary but
Upvotes: 0
Reputation: 103305
You could use MongoDB's aggregation framework to get the desired result. The aggregation pipeline would consist of an initial step which has a $match
operator that filters the documents based on the criteria above. The next pipeline stage would be the $unwind
operator that deconstructs the messages array from the input documents to output a document for each element. A further $match
filter then returns only the documents with the participant id. The final step with the $project
operator then passes along the documents with only the specified fields to the result:
db.collection.aggregate([
{
"$match": {
"_id" : ObjectId("5548b2b79b9567341c77d352"),
"messages.participants": ObjectId("5534b2992a104ed914435c31")
}
},
{
"$unwind": "$messages"
},
{
"$match": {
"messages.participants": ObjectId("5534b2992a104ed914435c31")
}
},
{
"$project": {
"_id": 0,
"messages": 1
}
}
])
Result:
/* 0 */
{
"result" : [
{
"messages" : {
"subject" : "fresh subject ",
"from" : ObjectId("5534b2992a104ed914435c31"),
"_id" : ObjectId("5548b5dab9279faf1c1b8688"),
"created" : ISODate("2015-05-05T12:21:46.261Z"),
"read" : true,
"message" : "fresh message ",
"participants" : [
ObjectId("5534b2992a104ed914435c31"),
ObjectId("5530af38576214dd3553331c")
]
}
}
],
"ok" : 1
}
In Mongoose you could use the same aggregation pipeline as follows:
// Using the pipeline builder
Model.aggregate({
"$match: {
""_id" : ObjectId("5548b2b79b9567341c77d352"),
"messages.participants": ObjectId("5534b2992a104ed914435c31")
}
})
.unwind("messages")
.match({ "messages.participants": ObjectId("5534b2992a104ed914435c31") })
.project({
"_id": 0,
"messages": 1
})
.exec(function (err, res) {
if (err) return handleError(err);
console.log(res);
});
// Or the simple aggregate method
var pipeline = [
{
"$match": {
"_id" : ObjectId("5548b2b79b9567341c77d352"),
"messages.participants": ObjectId("5534b2992a104ed914435c31")
}
},
{
"$unwind": "$messages"
},
{
"$match": {
"messages.participants": ObjectId("5534b2992a104ed914435c31")
}
},
{
"$project": {
"_id": 0,
"messages": 1
}
}
]
Model.aggregate(pipeline, function (err, res) {
if (err) return handleError(err);
console.log(res);
});
Upvotes: 2