MongoDB查询集合组差集
MongoDB query for set difference of collection groups
给定一组 modified
条记录和一组 original
条记录。我希望能够编写一个查询,该查询基本上会给我从 original
"set" 到 modified
"set".
的设置差异
所以给定两个集合,original
和 modified
像这样:
{ "_id" : 1, "set": "original", "key" : "foo", "element" : "bar" }
{ "_id" : 2, "set": "original", "key" : "bar", "element" : "old" }
{ "_id" : 3, "set": "original", "key" : "qux", "element" : "abc" } # Deleted
{ "_id" : 4, "set": "modified", "key" : "foo", "element" : "bar" } # Unchanged
{ "_id" : 5, "set": "modified", "key" : "bar", "element" : "new" } # Changed
{ "_id" : 6, "set": "modified", "key" : "baz", "element" : "bar" } # Created
我想从差异查询中获得某种结果,这些结果要么看起来像一组可游标的文档,例如:
{ "_id" : 3, "deleted": True}
{ "_id" : 5, "changed": True}
{ "_id" : 6, "created": True}
或不太理想(只是因为它不像 cursor
-able):
{
"deleted": [3],
"changed": [5],
"created": [6]
}
我并不局限于结果格式,而是只想弄清楚如何进行此计算并想展示我正在寻找的东西。
我看到 Mongo 具有 $setDifference
功能,但我无法将其应用于我的问题。
您可以使用以下聚合:
db.col.aggregate([
{
$group: {
_id: "$key",
docs: { $push: "$$ROOT" },
lastId: { $last: "$_id" }
}
},
{
$project: {
_id: 1,
lastId: 1,
original: { $arrayElemAt: [ { $filter: { input: "$docs", as: "d", cond: { $eq: [ "$$d.set", "original" ] } } } , 0 ] },
modified: { $arrayElemAt: [ { $filter: { input: "$docs", as: "d", cond: { $eq: [ "$$d.set", "modified" ] } } } , 0 ] }
}
},
{
$project: {
_id: 1,
lastId: 1,
state: {
$switch: {
branches: [
{ case: { $eq: [ "$original", undefined ] }, then: "created" },
{ case: { $eq: [ "$modified", undefined ] }, then: "deleted" },
{ case: { $ne: [ "$modified.element", "$original.element" ] }, then: "changed" }
],
default: "notModified"
}
}
}
},
{
$group: {
_id: "$state",
ids: { $push: "$lastId" }
}
},
{
$match: {
_id: { $ne: "notModified" }
}
},
{
$group: {
_id: null,
stats: { $push: { k: "$_id", v: "$ids" } }
}
},
{
$replaceRoot: {
newRoot: {
$arrayToObject: "$stats"
}
}
}
])
最初您需要使用 $group with $filter to get modified
and original
fields per key
. Then you can use $switch to determine state based on those two fields. Finally you can $group
again (by this state
) and use $arrayToObject with $replaceRoot 运算符根据检测到的状态动态获取您的密钥。最终结果:
{ "deleted" : [ 3 ], "changed" : [ 5 ], "created" : [ 6 ] }
编辑:或者,您可以使用以下聚合获得每个键的单个文档:
db.col.aggregate([
{
$group: {
_id: "$key",
docs: { $push: "$$ROOT" },
lastId: { $last: "$_id" }
}
},
{
$project: {
_id: 1,
lastId: 1,
original: { $arrayElemAt: [ { $filter: { input: "$docs", as: "d", cond: { $eq: [ "$$d.set", "original" ] } } } , 0 ] },
modified: { $arrayElemAt: [ { $filter: { input: "$docs", as: "d", cond: { $eq: [ "$$d.set", "modified" ] } } } , 0 ] }
}
},
{
$project: {
_id: 1,
lastId: 1,
state: {
$switch: {
branches: [
{ case: { $eq: [ "$original", undefined ] }, then: "created" },
{ case: { $eq: [ "$modified", undefined ] }, then: "deleted" },
{ case: { $ne: [ "$modified.element", "$original.element" ] }, then: "changed" }
],
default: "notModified"
}
}
}
},
{
$match: {
state: { $ne: "notModified" }
}
},
{
$project: {
_id: "$lastId",
state: 1
}
}
])
输出:
{ "state" : "created", "_id" : 6 }
{ "state" : "changed", "_id" : 5 }
{ "state" : "deleted", "_id" : 3 }
给定一组 modified
条记录和一组 original
条记录。我希望能够编写一个查询,该查询基本上会给我从 original
"set" 到 modified
"set".
所以给定两个集合,original
和 modified
像这样:
{ "_id" : 1, "set": "original", "key" : "foo", "element" : "bar" }
{ "_id" : 2, "set": "original", "key" : "bar", "element" : "old" }
{ "_id" : 3, "set": "original", "key" : "qux", "element" : "abc" } # Deleted
{ "_id" : 4, "set": "modified", "key" : "foo", "element" : "bar" } # Unchanged
{ "_id" : 5, "set": "modified", "key" : "bar", "element" : "new" } # Changed
{ "_id" : 6, "set": "modified", "key" : "baz", "element" : "bar" } # Created
我想从差异查询中获得某种结果,这些结果要么看起来像一组可游标的文档,例如:
{ "_id" : 3, "deleted": True}
{ "_id" : 5, "changed": True}
{ "_id" : 6, "created": True}
或不太理想(只是因为它不像 cursor
-able):
{
"deleted": [3],
"changed": [5],
"created": [6]
}
我并不局限于结果格式,而是只想弄清楚如何进行此计算并想展示我正在寻找的东西。
我看到 Mongo 具有 $setDifference
功能,但我无法将其应用于我的问题。
您可以使用以下聚合:
db.col.aggregate([
{
$group: {
_id: "$key",
docs: { $push: "$$ROOT" },
lastId: { $last: "$_id" }
}
},
{
$project: {
_id: 1,
lastId: 1,
original: { $arrayElemAt: [ { $filter: { input: "$docs", as: "d", cond: { $eq: [ "$$d.set", "original" ] } } } , 0 ] },
modified: { $arrayElemAt: [ { $filter: { input: "$docs", as: "d", cond: { $eq: [ "$$d.set", "modified" ] } } } , 0 ] }
}
},
{
$project: {
_id: 1,
lastId: 1,
state: {
$switch: {
branches: [
{ case: { $eq: [ "$original", undefined ] }, then: "created" },
{ case: { $eq: [ "$modified", undefined ] }, then: "deleted" },
{ case: { $ne: [ "$modified.element", "$original.element" ] }, then: "changed" }
],
default: "notModified"
}
}
}
},
{
$group: {
_id: "$state",
ids: { $push: "$lastId" }
}
},
{
$match: {
_id: { $ne: "notModified" }
}
},
{
$group: {
_id: null,
stats: { $push: { k: "$_id", v: "$ids" } }
}
},
{
$replaceRoot: {
newRoot: {
$arrayToObject: "$stats"
}
}
}
])
最初您需要使用 $group with $filter to get modified
and original
fields per key
. Then you can use $switch to determine state based on those two fields. Finally you can $group
again (by this state
) and use $arrayToObject with $replaceRoot 运算符根据检测到的状态动态获取您的密钥。最终结果:
{ "deleted" : [ 3 ], "changed" : [ 5 ], "created" : [ 6 ] }
编辑:或者,您可以使用以下聚合获得每个键的单个文档:
db.col.aggregate([
{
$group: {
_id: "$key",
docs: { $push: "$$ROOT" },
lastId: { $last: "$_id" }
}
},
{
$project: {
_id: 1,
lastId: 1,
original: { $arrayElemAt: [ { $filter: { input: "$docs", as: "d", cond: { $eq: [ "$$d.set", "original" ] } } } , 0 ] },
modified: { $arrayElemAt: [ { $filter: { input: "$docs", as: "d", cond: { $eq: [ "$$d.set", "modified" ] } } } , 0 ] }
}
},
{
$project: {
_id: 1,
lastId: 1,
state: {
$switch: {
branches: [
{ case: { $eq: [ "$original", undefined ] }, then: "created" },
{ case: { $eq: [ "$modified", undefined ] }, then: "deleted" },
{ case: { $ne: [ "$modified.element", "$original.element" ] }, then: "changed" }
],
default: "notModified"
}
}
}
},
{
$match: {
state: { $ne: "notModified" }
}
},
{
$project: {
_id: "$lastId",
state: 1
}
}
])
输出:
{ "state" : "created", "_id" : 6 }
{ "state" : "changed", "_id" : 5 }
{ "state" : "deleted", "_id" : 3 }