我有一个Mongo集合,其中的文档从未更新,而是读取了最新文档,并插入了一个新文档,其中某些字段已更新。这些通用文档共享一个标识符document_identifier
,以将它们与其他文档区分开。
我想执行以下查询:
获取所有customer_id
为X的文档,将其按document_identifier
分组,然后从每个组中取出带有最大updated_at
时间戳的文档。它应该完整返回文档(所有属性)。
示例数据集:
{
document_identifier: "abc",
updated_at: 1000,
customer_id: "123",
...
},
{
document_identifier: "def",
updated_at: 1001,
customer_id: "123",
...
},
{
document_identifier: "abc",
updated_at: 1002,
customer_id: "123",
...
},
{
document_identifier: "def",
updated_at: 10003,
customer_id: "123",
...
},
{
document_identifier: "xyz",
updated_at: 1004,
customer_id: "999",
...
},
{
document_identifier: "abc",
updated_at: 1005,
customer_id: "123",
...
},
{
document_identifier: "def",
updated_at: 1006,
customer_id: "123",
...
},
在上面的示例中,如果我要查询“ 123”的customer_id
,结果将是:
{
document_identifier: "abc",
updated_at: 1005,
customer_id: "123",
...
},
{
document_identifier: "def",
updated_at: 1006,
customer_id: "123",
...
},
我已经转向Mongo聚合框架,但似乎无法理解。
非常感谢您的帮助。
编辑:这是我现在所拥有的,它似乎正在工作,但是我不确定这是最佳的:
db.my_colleciton.aggregate([
{
$match: {customer_id: <value to query on>}
},
{
$sort: {updated_at: -1}
},
{
$group: {
_id: "$document_identifier",
my_doc: {$first: "$$ROOT"}
}
},
{
"$replaceRoot": {newRoot: "$my_doc"}
}
])
答案 0 :(得分:0)
因此,如果我理解正确,我认为此查询可能会有所帮助...
db.records.aggregate(
[
{ $group: {
_id: {customer_id: "$customer_id", document_identifier: "$document_identifier"},
max_updated_at: { $max: "$updated_at" }
}}
])
想法是将两个字段customer_id
和document_identifier
分组。对于该组合,请显示最大updated_at
,该数字应为滚动整数。
对于您提供的结果显示的数据集...
{ "_id" : { "customer_id" : "123", "document_identifier" : "def" }, "max_updated_at" : 10003 }
{ "_id" : { "customer_id" : "999", "document_identifier" : "xyz" }, "max_updated_at" : 1004 }
{ "_id" : { "customer_id" : "123", "document_identifier" : "abc" }, "max_updated_at" : 1005 }
输出的格式与您的示例不同。可以,还是您需要输出的格式来匹配示例?
编辑: 因此,OP请求输出的格式与问题中描述的预期格式匹配。事不宜迟...
db.records.aggregate(
[
{ $group: {
_id: {customer_id: "$customer_id", document_identifier: "$document_identifier"},
max_updated_at: { $max: "$updated_at" }
}},
{ $project: {
_id: 0,
document_identifier: "$_id.document_identifier",
updated_at: "$max_updated_at",
customer_id: "$_id.customer_id"
}}
]
)
现在输出如下:
{ "document_identifier" : "def", "updated_at" : 10003, "customer_id" : "123" }
{ "document_identifier" : "xyz", "updated_at" : 1004, "customer_id" : "999" }
{ "document_identifier" : "abc", "updated_at" : 1005, "customer_id" : "123" }
编辑编号2:
好,因此OP具有比问题中所代表的更多的字段,并且希望查看所有用于匹配文档的字段。这是到目前为止的查询...
db.records.aggregate(
[
{ $match: { customer_id: "123" }},
{ $group: {
_id: {customer_id: "$customer_id", document_identifier: "$document_identifier"},
max_updated_at: { $max: "$updated_at" }
}},
{ $lookup: {
from: "records",
let: {
customer_id: "$_id.customer_id",
document_identifier: "$_id.document_identifier",
max_updated_at: "$max_updated_at"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: [ "$customer_id", "$$customer_id"] },
{ $eq: [ "$document_identifier", "$$document_identifier"] },
{ $eq: [ "$updated_at", "$$max_updated_at"] }
]
}
}
}
],
as: "result"
}},
{ $unwind: "$result" } ,
{ $replaceRoot: { newRoot: "$result" } }
]
)
现在,这首先匹配客户ID。然后,它使用$ lookup和$ replaceRoot进行自我联接,以仅显示原始文档。不管存在多少字段,这都会保留原始文档格式。
输出:
{ "_id" : ObjectId("5db07a5d3cf0c979dd020f85"), "document_identifier" : "def", "updated_at" : 10003, "customer_id" : "123" }
{ "_id" : ObjectId("5db07a5d3cf0c979dd020f87"), "document_identifier" : "abc", "updated_at" : 1005, "customer_id" : "123" }
答案 1 :(得分:0)
首先按updated_at
降序排序 ,然后按document_identifier
依次$group
排序,然后通过$first
为该特定组选择第一个文档。
并保留与 $first
相同的字段。
查询: Demo Link
db.collection.aggregate([
{ $sort: { updated_at: -1 } },
{
$group: {
_id: "$document_identifier",
document_identifier: { $first: "$document_identifier" },
updated_at: { $first: "$updated_at" },
customer_id: { $first: "$customer_id" }
}
}
]).pretty();
结果:
{
"_id" : "abc",
"document_identifier" : "abc",
"updated_at" : 1005,
"customer_id" : "123"
},
{
"_id" : "xyz",
"document_identifier" : "xyz",
"updated_at" : 1004,
"customer_id" : "999"
},
{
"_id" : "def",
"document_identifier" : "def",
"updated_at" : 10003,
"customer_id" : "123"
}