使用聚合框架传递值

Pass Through Values Using Aggregation Framework

我在 Mongo 中有以下文档架构:

{ 
    "_id": "an id",
    "title": "my title",
    "muted": "true",
    "participants": [{ "userid":12345, "more": "data" }, ... ],
    "messages": [{ "message", "details " } ... { } ]
}

我正在尝试获取以下形式的对象数组:

[
    { 
        "_id": "an id", 
        "meta" 
        { 
            "title": "my title",
            "muted": "true",
            "participants": [12345, /* user ids only */ ],
        },
        "messages": [{ "message", "details " } ... { } ]
    }
]

我已经让聚合工作来生成消息和 _id:

[
    { $match:
            {
                'participants.user_id': userId
            }
    },
    { $unwind: "$messages" },
    { $match: { 'messages.sent_at': { '$gte': new Date(date) }}},
    { $group: { _id: "$_id", messages: { $addToSet: "$messages" }}}
]

获取元数据需要什么魔法?

如果您只想在输出中匹配 'participants.userid': 12345 "participants"

db.collection.aggregate(
[    
    { $match:
            {
                'participants.userid': 12345
            }
    },
    { $unwind : "$participants"},    
    { $match:
            {
                'participants.userid': 12345
            }
    },
    { $unwind: "$messages" },    
    { $group: { _id: "$_id" , muted : { $first : '$muted'}, title : { $first : '$title'}, messages: { $addToSet: "$messages" }, participants: { $addToSet: "$participants.userid" }}},
    { $project : { "messages" : "$messages" ,'meta.muted': '$muted', 'meta.title': '$title', 'meta.participants': '$participants'} },
]
).result

如果你想要 participants 中的所有用户 ID,不管它是什么。

db.collection.aggregate(
[
    { $match:
            {
                'participants.userid': 12345
            }
    },
    { $project : { "messages" : 1 ,"muted" : 1 , "title" : 1 , "messages" : 1 , "participants" : 1, "ids" : "$participants.userid"  } },
    { $unwind : "$participants"},    
    { $match:
            {
                'participants.userid': 12345
            }
    },
    { $unwind: "$messages" },    
    { $group: { _id: "$_id" , 
         muted : { $first : '$muted'}, title : { $first : '$title'}, 
         ids : { $first : '$ids'},
         messages: { $addToSet: "$messages" },
         participants: { $addToSet: "$participants.userid" }}},
    { $project : { "messages" : "$messages" ,'meta.muted': '$muted', 'meta.title': '$title', 'meta.participants': '$ids'} },
]
).result

输出:

{
    "0" : {
        "_id" : "an id",
        "messages" : [ 
            {
                "message2" : "details2 "
            }, 
            {
                "message" : "details "
            }
        ],
        "meta" : {
            "muted" : "true",
            "title" : "my title",
            "participants" : [ 
                 12345
            ]
        }
    }
}

在最后一个 $group 语句中,您需要告诉 Mongo 它应该 return 哪些字段。目前,您只需要 _idmessages 字段。假设您聚合了 return 三个这样的文档:

{ 
  "_id": 1111,
  "title": "my title",
  "muted": "true",
  "participants": [{ "userid":12345, "more": "data" }, ... ],
  "messages": { "message": "Foo" }
},
{ 
  "_id": 1111,
  "title": "my title",
  "muted": "true",
  "participants": [{ "userid":12345, "more": "data" }, ... ],
  "messages": { "message": "Bar" }
},
{ 
  "_id": 1111,
  "title": "my title",
  "muted": "true",
  "participants": [{ "userid":12345, "more": "data" }, ... ],
  "messages": { "message": "Baz" }
}

您已经在向 Mongo 请求使用 $push 运算符的所有消息的列表,所以我们已经涵盖了。对于其他字段,您不能这样做:

{$group: {
  _id: "$_id", 
  title: 1,
  muted: "$muted"
}}

毕竟,Mongo 如何知道如何处理三个 "my title" 值?还是muted的三个布尔值?做一个数组?丢弃数据?连接它们?

在这种情况下,由于所有三个值将始终相同(根据定义),您可以说 "I don't care, just give me any one of them"、"give me the second result"、"give me the first" 或 "give me the last"。前两个不可能,所以我们只剩下 $first$last:

{$group: {
  _id: "$_id", 
  title: {$first: "$title"},
  muted: {$first: "$muted"}
}}

当然,在这种情况下使用哪一个并不重要。