For user1=1 and user2, message hiii0 should only come
For user1=1 and user3, message hiii2 should only come
For user1=1 and user4, message hiii1 should only come
上面的mongodb集合商店在user1和user2之间聊天。 我正在寻找一个查询,它将给我最新消息的结果 message.sender =每行1个。
即寻找3行作为输出
db.chat.find({"messages.sender":1})
即。只有三排。
db.chat.aggregate([
{$unwind:"$messages"},
{$match:{"messages.sender":1}},
{$sort:{"messages.datetime":-1}
])
正在提供所有行,而我正在寻找具有最新日期时间的匹配行。
请帮忙
示例:
{ "_id" : ObjectId("593921425ccc8150f35e7663"), "user1" : 1, "user2" : 3, "messages" : { "sender" : 1, "datetime" : ISODate("2017-06-10T10:04:50Z"), "body" : "hiii 2" } }
{ "_id" : ObjectId("593921425ccc8150f35e7664"), "user1" : 1, "user2" : 4, "messages" : { "sender" : 1, "datetime" : ISODate("2017-06-09T10:04:50Z"), "body" : "hiii 1" } }
{ "_id" : ObjectId("593921425ccc8150f35e7662"), "user1" : 1, "user2" : 2, "messages" : { "sender" : 1, "datetime" : ISODate("2017-06-08T10:04:50Z"), "body" : "hiii 0" } }
{ "_id" : ObjectId("593921425ccc8150f35e7663"), "user1" : 1, "user2" : 3, "messages" : { "sender" : 1, "datetime" : ISODate("2017-06-08T10:04:50Z"), "body" : "hiii 0" } }
{ "_id" : ObjectId("593921425ccc8150f35e7664"), "user1" : 1, "user2" : 4, "messages" : { "sender" : 1, "datetime" : ISODate("2017-06-08T10:04:50Z"), "body" : "hiii 0" } }
正在输出
@Bean DateProvider dateProvider()
最后两行不可取,因为它不是user1-user2记录的最新记录。
如果我要添加{$ limit:1},它只给出一行。
答案 0 :(得分:1)
这里的基本概念是您需要聚合框架才能应用条件来“过滤”数组元素到条件。根据可用的版本,可以应用不同的技术。
在所有情况下都是结果:
{
"_id" : ObjectId("593921425ccc8150f35e7664"),
"user1" : 1,
"user2" : 4,
"messages" : {
"sender" : 1,
"datetime" : ISODate("2017-06-09T10:04:50Z"),
"body" : "hiii 1"
}
}
{
"_id" : ObjectId("593921425ccc8150f35e7663"),
"user1" : 1,
"user2" : 3,
"messages" : {
"sender" : 1,
"datetime" : ISODate("2017-06-10T10:04:50Z"),
"body" : "hiii 2"
}
}
{
"_id" : ObjectId("593921425ccc8150f35e7662"),
"user1" : 1,
"user2" : 2,
"messages" : {
"sender" : 1,
"datetime" : ISODate("2017-06-08T10:04:50Z"),
"body" : "hiii 0"
}
}
db.chat.aggregate([
{ "$match": { "messages.sender": 1 } },
{ "$replaceRoot": {
"newRoot": {
"$let": {
"vars": {
"messages": {
"$filter": {
"input": "$messages",
"as": "m",
"cond": { "$eq": [ "$$m.sender", 1 ] }
}
},
"maxDate": {
"$max": {
"$map": {
"input": {
"$filter": {
"input": "$messages",
"as": "m",
"cond": { "$eq": [ "$$m.sender", 1 ] }
}
},
"as": "m",
"in": "$$m.datetime"
}
}
}
},
"in": {
"_id": "$_id",
"user1": "$user1",
"user2": "$user2",
"messages": {
"$arrayElemAt": [
{ "$filter": {
"input": "$$messages",
"as": "m",
"cond": { "$eq": [ "$$m.datetime", "$$maxDate" ] }
}},
0
]
}
}
}
}
}}
])
这是利用$replaceRoot
的最有效方式,它允许我们使用$let
声明要在“替换”结构中使用的变量。这里的主要优点是这只需要“两个”流水线阶段。
为了匹配数组内容,您使用$filter
应用$eq
逻辑运算来测试"sender"
的值。在条件匹配的情况下,只返回匹配的数组条目。
使用相同的$filter
以便仅考虑匹配的“发件人”条目,然后我们希望将$max
应用于“已过滤”列表中"datetime"
中的值。 $max
] 5值是条件的“最新”日期。
我们想要这个值,以便稍后我们可以将“过滤”数组的返回结果与此“maxDate”进行比较。这是在$let
"in"
块内发生的事情,其中为过滤内容先前声明的两个“变量”和“maxDate”再次应用于$filter
以便返回应该返回的内容是唯一符合“最新日期”条件的价值。
由于您只想要“一个”结果,我们使用$arrayElemAt
来使用值而不是数组。
db.chat.aggregate([
{ "$match": { "messages.sender": 1 } },
{ "$project": {
"user1": 1,
"user2": 1,
"messages": {
"$filter": {
"input": "$messages",
"as": "m",
"cond": { "$eq": [ "$$m.sender", 1 ] }
}
},
"maxDate": {
"$max": {
"$map": {
"input": {
"$filter": {
"input": "$messages",
"as": "m",
"cond": { "$eq": [ "$$m.sender", 1 ] }
}
},
"as": "m",
"in": "$$m.datetime"
}
}
}
}},
{ "$project": {
"user1": 1,
"user2": 1,
"messages": {
"$arrayElemAt":[
{ "$filter": {
"input": "$messages",
"as": "m",
"cond": { "$eq": [ "$$m.datetime", "$maxDate" ] }
}},
0
]
}
}}
])
这基本上与描述的过程相同,但没有$replaceRoot
管道阶段,我们需要在两个$project
阶段应用。这样做的原因是我们需要“maxDate”中的“计算值”来执行最终$filter
,并且它不能在复合语句中执行,因此我们拆分管道。这对整体运营成本影响很小。
在MongoDB 2.6到3.0中,我们可以使用除$arrayElemAt
之外的大多数技术,并使用单个条目接受“数组”结果或放入$unwind
阶段来处理应该现在只需一个条目。
db.chat.aggregate([
{ "$match": { "messages.sender": 1 } },
{ "$unwind": "$messages" },
{ "$match": { "messages.sender": 1 } },
{ "$sort": { "_id": 1, "messages.datetime": -1 } },
{ "$group": {
"_id": "$_id",
"user1": { "$first": "$user1" },
"user2": { "$first": "$user2" },
"messages": { "$first": "$messages" }
}}
])
虽然看起来很简短,但这是迄今为止成本最高的操作。在这里,您必须使用$unwind
才能将条件应用于数组元素。这是一个非常昂贵的过程,因为它为每个数组条目生成每个文档的副本,并且基本上被在“过滤”情况下避免这种情况的现代运算符所取代。
此处的第二个$match
阶段会丢弃与“发件人”条件不匹配的任何元素(现在为“文档”)。然后我们应用$sort
以便_id
将每个文档的“最新”日期置于顶部,因此两个“排序”键。