Node.js 将合并查找结果聚合到主文档
我创建了一个函数来缝合来自不同集合的2条记录: 第1条记录:Node.js 将合并查找结果聚合到主文档,node.js,mongodb,aggregation-framework,Node.js,Mongodb,Aggregation Framework,我创建了一个函数来缝合来自不同集合的2条记录: 第1条记录: { _id: objectId(1231242331233), acc: '12390', val2: 'asdasdas' } 收集2记录: { _id: objectId(989232382302308), isValid: '1', tf: '098789928', acc: '12390' } 为此,我提出了以下带有$lookup的聚合函数 Collection2.a
{
_id: objectId(1231242331233),
acc: '12390',
val2: 'asdasdas'
}
收集2记录:
{
_id: objectId(989232382302308),
isValid: '1',
tf: '098789928',
acc: '12390'
}
为此,我提出了以下带有$lookup的聚合函数
Collection2.aggregate([
{
$lookup:
{
from: "Collection1",
localField: "acc",
foreignField: "acc",
as: "acc_record"
}
}
{
$out: 'Collection3'
}
]);
这将生成具有以下结构的记录的集合3:
{
_id: objectId(989232382302308),
isValid: '1',
tf: '098789928',
acc: '12390',
acc_record:[
{
_id: objectId(1231242331233),
acc: '12390',
val2: 'asdasdas'
}
]
}
合并这两条记录的聚合函数是什么,而不是将Collection1记录放在json对象的更深层次,只放置不相等的元素并合并具有相同名称的元素
因此,最终记录结果将是:
{
_id: objectId(989232382302308),
isValid: '1',
tf: '098789928',
acc: '12390',
val2: 'asdasdas'
}
附加模块:
和用于引用数组中的值,并将其升级为顶级对象中的值
如果您总是知道结果是“一对一”的,并且可以简单地从返回的第一个数组元素中获取值,那么这很好。如果它们是“一对多”,那么您也可以申请:
这对于“一对一”也是完全有效的,但是您应该注意,\u id
在这里是“故意”删除的。原因是,对于“多个”结果,会为结果中返回的每个数组成员生成父文档的“多个”副本。由于\u id
是“主键”,因此不能在“多个文档”中保持该值相同
因此,丢弃主键的意义在于,这样可以在写入时创建一个新值,而不会因“重复键错误”而失败。或者,如果希望将其保留为“引用”,则只需将“$\u id”
值重命名为
对于更大的输出,我们可以使用一些技巧来“合并”MongoDB支持的特性。在当前版本中,这些是和来自MongoDB 3.4.4及更高版本:
Collection2.aggregate([
{ "$lookup":{
"from": "Collection1",
"localField": "acc",
"foreignField": "acc",
"as": "acc_record"
}},
{ "$unwind": "$acc_record" },
{ "$replaceRoot": {
"newRoot": {
"$arrayToObject": {
"$concatArrays": [
{ "$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$not": { "$in": ["$$this.k", ["_id", "acc_record"] } }
}},
{ "$filter": {
"input": { "$objectToArray": "$acc_record" },
"cond": { "$ne": ["$$this.k", "acc"] }
}}
]
}
}
}},
{ "$out": "Collection3" }
])
诀窍是将“根”文档和子数组内容都转换为单独的数组,过滤掉重叠的键并应用它们,使它们成为一个数组。然后,您可以应用“连接”结果,并通过将其转换为根文档
MongoDB 3.6
MongoDB 3.6使其更加简单,并引入了一些新功能,因此您可以真正做一些简单的事情,如:
Collection2.aggregate([
{ "$lookup":{
"from": "Collection1",
"localField": "acc",
"foreignField": "acc",
"as": "acc_record"
}},
{ "$unwind": "$acc_record" },
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [
{ "$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$not": { "$in": ["$$this.k", ["_id", "acc_record","acc"] } },
}
},
"$acc_record"
]
}
}},
{ "$out": "Collection3" }
]);
通常情况下,您仍然希望输入不需要的键,例如的目标字段名,很可能还有“localField”
或“foreignField”
值。因此,除非您准备添加另一个聚合阶段以完全删除该子项,否则您实际上不能仅使用“$ROOT”
与子项的内容合并
因此,一般来说,这里并没有添加太多内容,当然,操作符的命名使代码的意图非常清楚。加载项:
和用于引用数组中的值,并将其升级为顶级对象中的值
如果您总是知道结果是“一对一”的,并且可以简单地从返回的第一个数组元素中获取值,那么这很好。如果它们是“一对多”,那么您也可以申请:
这对于“一对一”也是完全有效的,但是您应该注意,\u id
在这里是“故意”删除的。原因是,对于“多个”结果,会为结果中返回的每个数组成员生成父文档的“多个”副本。由于\u id
是“主键”,因此不能在“多个文档”中保持该值相同
因此,丢弃主键的意义在于,这样可以在写入时创建一个新值,而不会因“重复键错误”而失败。或者,如果希望将其保留为“引用”,则只需将“$\u id”
值重命名为
对于更大的输出,我们可以使用一些技巧来“合并”MongoDB支持的特性。在当前版本中,这些是和来自MongoDB 3.4.4及更高版本:
Collection2.aggregate([
{ "$lookup":{
"from": "Collection1",
"localField": "acc",
"foreignField": "acc",
"as": "acc_record"
}},
{ "$unwind": "$acc_record" },
{ "$replaceRoot": {
"newRoot": {
"$arrayToObject": {
"$concatArrays": [
{ "$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$not": { "$in": ["$$this.k", ["_id", "acc_record"] } }
}},
{ "$filter": {
"input": { "$objectToArray": "$acc_record" },
"cond": { "$ne": ["$$this.k", "acc"] }
}}
]
}
}
}},
{ "$out": "Collection3" }
])
诀窍是将“根”文档和子数组内容都转换为单独的数组,过滤掉重叠的键并应用它们,使它们成为一个数组。然后,您可以应用“连接”结果,并通过将其转换为根文档
MongoDB 3.6
MongoDB 3.6使其更加简单,并引入了一些新功能,因此您可以真正做一些简单的事情,如:
Collection2.aggregate([
{ "$lookup":{
"from": "Collection1",
"localField": "acc",
"foreignField": "acc",
"as": "acc_record"
}},
{ "$unwind": "$acc_record" },
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [
{ "$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$not": { "$in": ["$$this.k", ["_id", "acc_record","acc"] } },
}
},
"$acc_record"
]
}
}},
{ "$out": "Collection3" }
]);
通常情况下,您仍然希望输入不需要的键,例如的目标字段名,很可能还有“localField”
或“foreignField”
值。因此,除非您准备添加另一个聚合阶段以完全删除该子项,否则您实际上不能仅使用“$ROOT”
与子项的内容合并
因此,一般来说,除了操作符的命名使代码的意图非常清晰之外,这里的添加并不多。我是否需要引用$project中Collection2中的所有记录?Collection2表示只有一个例子,我的实际集合由超过50个属性的记录组成。让这项工作变得麻烦。@Joaofilipeclementematins仍在写作。我要说了。在将来,你实际上需要在“你的问题”中详细说明这些细节。这些是使用
$out
完成此操作的完整方法。您还需要使用游标并对其进行迭代以转换输出,然后进行回写。我是否需要引用$project中Collection2中的所有记录?Collection2表示只有一个例子,我的实际集合由超过50个属性的记录组成。让这项工作变得麻烦。@Joaofilipeclementematins仍在写作。我要说了。在将来,你实际上需要在“你的问题”中详细说明这些细节。这些是使用$out
完成此操作的完整方法。您还可以使用游标并对其进行迭代以转换输出,然后进行回写。在提供的答案中是否有您认为无法解决问题的内容?