MongoDB通过指定两个应匹配的字段来检索集合中数组的子集

时间:2012-02-08 13:31:31

标签: javascript mongodb

我正在使用这种结构来存储对话&消息:

{ "_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}}
      }
    }
  ]
})

还有其他几个选项尝试$而不是$或等等但它不起作用。无论接收者/发送者删除的字段是什么,它都不会返回任何内容或整个会话。

谢谢你, 迈克尔

2 个答案:

答案 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"
    }}});

第一场比赛不是必需的,但最好在开始时尽可能地过滤掉。