我正在学习Mongodb聚合函数,并且正在研究查询。我的文档如下所示。
[
{
"_id": 17,
"members": [{
"email": "[email protected]",
"status": "pending",
"joined": ISODate("2020-05-20T02:04:00Z")
},
{
"email": "[email protected]",
"status": "pending",
"joined": ISODate("2020-05-20T02:36:00Z")
}
],
"messages": [{
"c": "m1",
"ts": ISODate("2020-05-20T02:04:15Z")
},
{
"c": "m2",
"ts": ISODate("2020-05-20T02:36:31Z")
}
]
}
]
每个文档都有2个数组:成员和消息。我需要过滤成员中的一个元素(使用电子邮件),并根据与“ messages.ts”属性匹配的“ members.joined”属性过滤消息。
我尝试了不同的方法,但尚未实现。在下面的查询中,我对日期ISODate(“ 2020-05-20T02:36:00Z”)进行了硬编码,而不是使用member.joined属性。如何编写优化查询以实现相同目的?
db.coll.aggregate([
{
$match: {
_id: 17,
"members.email": "[email protected]"
}
},
{
$project: {
messages: {
$filter: {
input: "$messages",
as: "messs",
cond: {
$gte: [
"$$messs.ts",
ISODate("2020-05-20T02:36:00Z") // supposed to have members.$.joined property here
]
}
}
}
}
}
])
预期结果是应该打印的消息中的第二个元素。
您可以尝试以下聚合查询中的任何一个:
db.collection.aggregate([
{
$match: { _id: 17, "members.email": "[email protected]" }
},
/** If you need `members` array as is i.e; unfiltered in response, So instead of expensive iteration on `members` array we can get `joined` value as like below */
{
$addFields: {
messages: {
$let: {
vars: {
messagesArr: {
$reduce: {
input: "$messages",
initialValue: { data: [], joinedTime: { $arrayElemAt: [ "$members.joined", { $indexOfArray: [ "$members.email", "[email protected]" ] } ] } },
in: {
data: {
$cond: [ { $gte: [ "$$this.ts", "$$value.joinedTime" ] },
{ $concatArrays: [ "$$value.data", [ "$$this" ] ] }, // If condition is met concat holding array with new object
"$$value.data" // If not just return the holding array, doesn't add current object to array
]
},
joinedTime: "$$value.joinedTime" // maintaining joined value
}
}
}
},
in: "$$messagesArr.data" // return newly created array in `$reduce` using `$let`
}
}
}
}
])
测试: mongoplayground
参考: 聚合
因此,上面的查询将返回过滤后的messages
数组和原始members
数组。以防万一,如果您还需要members
过滤,然后在以下$addFields
阶段添加以下内容$match
(我们假设这email
是唯一的),这样做可以避免在大型数组上进行迭代:
{
$addFields: {
members: {
$arrayElemAt: [
"$members",
{
$indexOfArray: [
"$members.email",
"[email protected]"
]
}
]
}
}
}
当您执行上述操作时,members
将是一个已过滤的对象。这样$reduce
就可以了joinedTime: "$members.joined"
。
测试: mongoplayground
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句