问题
Considering I have the following documents in a collection (ignoring the _id
) :
[
{
"Id": "OP01",
"Sessions": [
{
"Id": "Session01",
"Conversations": [
{
"Id": "Conversation01",
"Messages": [
{
"Id": "Message01",
"Status": "read",
"Direction": "inbound"
},
{
"Id": "Message02",
"Status": "delivered",
"Direction": "internal"
},
{
"Id": "Message03",
"Status": "delivered",
"Direction": "inbound"
},
{
"Id": "Message04",
"Status": "sent",
"Direction": "outbound"
}
]
},
{
"Id": "Conversation02",
"Messages": [
{
"Id": "Message05",
"Status": "sent",
"Direction": "outbound"
}
]
}
]
},
{
"Id": "Session02",
"Conversations": [
{
"Id": "Conversation03",
"Messages": [
{
"Id": "Message06",
"Status": "read",
"Direction": "inbound"
},
{
"Id": "Message07",
"Status": "delivered",
"Direction": "internal"
}
]
},
{
"Id": "Conversation04",
"Messages": []
}
]
}
]
},
{
"Id": "OP02",
"Sessions": [
{
"Id": "Session03",
"Conversations": []
}
]
},
{
"Id": "OP03",
"Sessions": []
}
]
First query — aggregate (+$project
)
I want to get the list of Messages
grouped by their Conversations
where:
Sessions.Id: "Session01"
and
Sessions.Conversations.Messages.Direction $in ["inbound", "outbound"]
and
Sessions.Conversations.Messages.Status $in ["sent", "delivered"]
The expected result is:
[
{
"Id": "Conversation01",
"Messages": [
{
"Id": "Message03",
"Status": "delivered",
"Direction": "inbound"
},
{
"Id": "Message04",
"Status": "sent",
"Direction": "outbound"
}
]
},
{
"Id": "Conversation02",
"Messages": [
{
"Id": "Message05",
"Status": "sent",
"Direction": "outbound"
}
]
}
]
A side note:
If on different documents
(or on different Sessions
) the Sessions.Id: "Session01"
condition is verified ("Session01"
is not an unique key), the document
's Messages
that match the other conditions should also be added.
The result output doesn't mention neither the document
or Sessions
levels.
Second query — update
I want to update the Sessions.Conversations.Messages.Status
of all those messages (same condition as before) to "read"
.
The collection should have now the following documents:
Please note the changes on:
Sessions.Conversations.Messages.Id = "Message03"
Sessions.Conversations.Messages.Id = "Message04"
Sessions.Conversations.Messages.Id = "Message05"
at Sessions.Id = "Session01"
[
{
"Id": "OP01",
"Sessions": [
{
"Id": "Session01",
"Conversations": [
{
"Id": "Conversation01",
"Messages": [
{
"Id": "Message01",
"Status": "read",
"Direction": "inbound"
},
{
"Id": "Message02",
"Status": "delivered",
"Direction": "internal"
},
{
"Id": "Message03",
"Status": "read",
"Direction": "inbound"
},
{
"Id": "Message04",
"Status": "read",
"Direction": "outbound"
}
]
},
{
"Id": "Conversation02",
"Messages": [
{
"Id": "Message05",
"Status": "read",
"Direction": "outbound"
}
]
}
]
},
{
"Id": "Session02",
"Conversations": [
{
"Id": "Conversation03",
"Messages": [
{
"Id": "Message06",
"Status": "read",
"Direction": "inbound"
},
{
"Id": "Message07",
"Status": "delivered",
"Direction": "internal"
}
]
},
{
"Id": "Conversation04",
"Messages": []
}
]
}
]
},
{
"Id": "OP02",
"Sessions": [
{
"Id": "Session03",
"Conversations": []
}
]
},
{
"Id": "OP03",
"Sessions": []
}
]
How can I accomplish these results with an aggregate
and update_one
queries?
Here comes a visual explanation of both queries:
回答1:
I have written the aggregation query
db.session.aggregate([
{
$unwind:"$Sessions"
},
{
$unwind:"$Sessions.Conversations"
},
{
$unwind:"$Sessions.Conversations.Messages"
},
{
$match:{
"Sessions.Id" : "Session01",
"Sessions.Conversations.Messages.Direction":{
$in:[
"inbound", "outbound"
]
},
"Sessions.Conversations.Messages.Status":{
$in:[
"sent", "delivered"
]
}
}
},
{
$group:{
"_id":"$Sessions.Conversations.Id",
"Messages":{
$push:"$Sessions.Conversations.Messages"
}
}
}
]).pretty()
Output
{
"_id" : "Conversation02",
"Messages" : [
{
"Id" : "Message05",
"Status" : "sent",
"Direction" : "outbound"
}
]
}
{
"_id" : "Conversation01",
"Messages" : [
{
"Id" : "Message03",
"Status" : "delivered",
"Direction" : "inbound"
},
{
"Id" : "Message04",
"Status" : "sent",
"Direction" : "outbound"
}
]
}
Now to Update the document:
I have used the positional-filters
db.session.update(
{},
{
$set:{
"Sessions.$[session].Conversations.$[].Messages.$[message].Status":"read"
}
},
{
"arrayFilters": [{"session.Id":"Session01"},{ "message.Id": "Message05" }]
}
)
This will update the status as read
for "session.Id":"Session01"
and "message.Id": "Message05"
Hope this will help you. :)
UPDATE
db.session.update(
{},
{
$set:{
"Sessions.$[session].Conversations.$[].Messages.$[message].Status":"read"
}
},
{
"arrayFilters": [
{
"session.Id":"Session01"
},
{
"message.Direction": {
$in :[
"inbound",
"outbound"
]
},
"message.Status": {
$in :[
"sent",
"delivered"
]
}
}
]
}
)
来源:https://stackoverflow.com/questions/61157587/filter-nested-array-with-conditions-based-on-multi-level-object-values-and-updat