我正在使用这种结构来存储对话&消息:
{ "_id" : ObjectId( "4f2952d7ff4b3c36d700000d" ),
"messages" : [
{ "_id" : ObjectId( "4f2952d7ff4b3c36d700000c" ),
"sender" : "4f02f16f0364c024678c0e5f",
"receiver" : "4f02f16f0364c024678c0e61",
"receiver_deleted" : "true",
"sender_deleted" : "true",
"body" : "MSG 1",
"timestamp" : "2012-02-01T14:57:27Z" },
{ "_id" : ObjectId( "4f2952daff4b3c36d700000e" ),
"sender" : "4f02f16f0364c024678c0e61",
"receiver" : "4f02f16f0364c024678c0e5f",
"body" : "MSG 2",
"timestamp" : "2012-02-01T14:57:30Z" },
{ "_id" : ObjectId( "4f295305ff4b3c36d700000f" ),
"sender" : "4f02f16f0364c024678c0e5f",
"receiver" : "4f02f16f0364c024678c0e61",
"body" : "TEST",
"timestamp" : "2012-02-01T14:58:13Z" } ],
"participants" : [
"4f02f16f0364c024678c0e5f",
"4f02f16f0364c024678c0e61" ],
"type" : "chat" }
当其中一个发件人或收件人确实删除了特定邮件时,receiver_deleted或sender_deleted会被添加到邮件中(如第一条邮件中所示)。
现在我如何才能仅使用未设置发件人/收件人已删除标志的邮件来获取对话?
首先,我尝试过这样:
db.conversations.find({
"_id": ObjectId("4f2952d7ff4b3c36d700000d"),
"participants": {"$in": ["4f02f16f0364c024678c0e5f"]},
"$or": [
{
"$and": [{"messages.sender": "4f02f16f0364c024678c0e5f"}, {"messages.sender_deleted": {"$exists": false}}]
},
{
"$and": [{"messages.receiver": "4f02f16f0364c024678c0e5f"}, {"messages.receiver_deleted": {"$exists": false}}]
}
]
})
但这不起作用。我也尝试过这样的$ elemMatch:
db.conversations.find({
"_id": ObjectId("4f2952d7ff4b3c36d700000d"),
"participants": {"$in": ["4f02f16f0364c024678c0e5f"]},
"$or": [
{
"messages": {
"$elemMatch": {"sender": "4f02f16f0364c024678c0e5f", "sender_deleted": {"$exists": False}}
}
},
{
"messages": {
"$elemMatch": {"receiver": "4f02f16f0364c024678c0e5f", "receiver_deleted": {"$exists": False}}
}
}
]
})
还有其他几个选项尝试$而不是$或等等但它不起作用。无论接收者/发送者删除的字段是什么,它都不会返回任何内容或整个会话。
谢谢你, 迈克尔
答案 0 :(得分:2)
目前无法使用mongodb检索数组的子集。如果匹配,您将始终返回整个文档,如果没有匹配,则无需返回任何内容。 $ slice允许你返回一个子集,但这是基于一个起始和停止索引(这不是你想要的 - 因为你只想返回数组中匹配的消息)。
您在此处描述的功能已在此处记录并请求:https://jira.mongodb.org/browse/SERVER-828
答案 1 :(得分:1)
版本2.2 Aggregation Framework可用。您可以像这样执行查询:
db.expose.aggregate(
//Find the Documents which contains the desired criteria (document level)
{
$match: {
$or: [
{
"messages.sender_deleted": "true"
},
{
"messages.receiver_deleted": "true"
}]}},
//Peels off the elements of messages array individually
{
$unwind: "$messages"
},
//Perform the same find method, now in the embed collection level
{
$match: {
$or: [
{
"messages.sender_deleted": "true"
},
{
"messages.receiver_deleted": "true"
}]}},
//Select what to show as the result: in this case the Document id and the messages array
{
$group: {
_id: "$_id",
messages: {
$push: "$messages"
}}});
第一场比赛不是必需的,但最好在开始时尽可能地过滤掉。