MongoDB: $lookup 在后续文档中使用相同的 collection
MongoDB: $lookup with the same collection over subsequent documents
我是 MongoDB 的新手,我必须转换我处理特定数据的方式和之前的 SQL 结构。所以,我现在的做法肯定不是最明智的。
我有一份包含大量信息的工作合同清单。在那个级别,他们不按个人分组。使用命令 $lookup
我想 link 每个合同(文件)与以下合同(如果与同一工人(个人)相关)。
有一个名为 'ord_id' 的特定字段,显示在原始 .csv table 中,它对文档进行排序。上面的例子是我的 collection 的简化版本。这些条目指的是同一个人 'worker_id': 158250
,但存在不同的其他人。
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e663"),
"worker_id" : "158250",
"employer" : "139998",
"start_date" : ISODate("2012-02-15T01:00:00.000+01:00"),
"end_date" : ISODate("2012-04-17T02:00:00.000+02:00"),
"ord_id" : 484
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e665"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2012-10-17T02:00:00.000+02:00"),
"end_date" : ISODate("2012-11-15T01:00:00.000+01:00"),
"ord_id" : 486
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e667"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2013-06-01T02:00:00.000+02:00"),
"end_date" : ISODate("2013-09-30T02:00:00.000+02:00"),
"ord_id" : 488
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e666"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2013-02-01T01:00:00.000+01:00"),
"end_date" : ISODate("2013-05-31T02:00:00.000+02:00"),
"ord_id" : 487
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e664"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2012-03-12T01:00:00.000+01:00"),
"end_date" : ISODate("2012-05-12T02:00:00.000+02:00"),
"ord_id" : 485
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e668"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2015-06-01T02:00:00.000+02:00"),
"end_date" : ISODate("2015-11-30T01:00:00.000+01:00"),
"ord_id" : 489
}
我想在每个文档中添加一个名为 'next' 的新字段,它引用以下基于 ord_id
的合同。为此,我执行了以下命令:
db.mycollection.aggregate([
{ $sort: { ord_id: 1 } },
{
$lookup:
{
from: "mycollection",
let: { id_lav: "$worker_id", curr_ord_id: "$ord_id" }, // 'curr_' is for current
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$worker_id", "$$id_lav" ] },
{ $gt: [ "$ord_id", "$$curr_ord_id" ] }
]
}
}
}, { $limit: 1 }
],
as: "next"
}
},
{ $unwind: { path: "$next", preserveNullAndEmptyArrays: true} },
{ $out: "mycollection" } ],
{ allowDiskUse: true } );
但是,我肯定遗漏了一些东西。事实上,某些文档的 'next' 字段与后面的有效字段不匹配。例如,'ord_id' 等于 484 的文档结果被 linked 到 'ord_id' 等于 486 而不是 485 的文档。相反,其他文档被 linked适当地。为了解决这个问题,我以这种方式稍微修改了以前的代码:
db.mycollection.aggregate([
{ $sort: { ord_id: 1 } },
{
$lookup:
{
from: "mycollection",
let: { id_lav: "$worker_id", curr_ord_id: "$ord_id" }, // 'curr_' is for current
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$worker_id", "$$id_lav" ] },
{ $gt: [ "$ord_id", "$$curr_ord_id" ] },
{ $eq: [ { $subtract: [ "$ord_id", "$$curr_ord_id" ] }, 1 ] },
{ $or: [
{ $eq: [ "$worker_id", "$$id_lav" ] },
{ $gt: [ "$ord_id", "$$curr_ord_id" ] }
] }
]
}
}
}, { $limit: 1 }
],
as: "next"
}
},
{ $unwind: { path: "$next", preserveNullAndEmptyArrays: true} },
{ $out: "mycollection" } ],
{ allowDiskUse: true } );
我完全不明白为什么第一个命令没有给出所需的输出。尽管如此,我相信有更好的方法来解决这个问题。任何建议表示赞赏。提前致谢!
您的第一个管道非常接近。主要问题是你必须在 $lookup
中 $sort
,你现在拥有的 $sort
是多余的(你可以保留它,这样新集合将在 [=14= 之后排序) ] 因此,如果您将来 运行 在同一更新中 $sort
将不再需要)。
db.mycollection.aggregate([
{
$lookup: {
from: "mycollection",
let: {
id_lav: "$worker_id",
curr_ord_id: "$ord_id"
},
/** 'curr_' is for current*/
pipeline: [
{
$sort: {
ord_id: 1
}
},
{
$match: {
$expr: {
$and: [
{
$eq: [
"$worker_id",
"$$id_lav"
]
},
{
$gt: [
"$ord_id",
"$$curr_ord_id"
]
}
]
}
}
},
{
$limit: 1
}
],
as: "next"
}
},
{
$unwind: {
path: "$next",
preserveNullAndEmptyArrays: true
}
},
{ $unwind: { path: "$next", preserveNullAndEmptyArrays: true} },
{ $out: "mycollection" }
],
{
allowDiskUse: true
})
我是 MongoDB 的新手,我必须转换我处理特定数据的方式和之前的 SQL 结构。所以,我现在的做法肯定不是最明智的。
我有一份包含大量信息的工作合同清单。在那个级别,他们不按个人分组。使用命令 $lookup
我想 link 每个合同(文件)与以下合同(如果与同一工人(个人)相关)。
有一个名为 'ord_id' 的特定字段,显示在原始 .csv table 中,它对文档进行排序。上面的例子是我的 collection 的简化版本。这些条目指的是同一个人 'worker_id': 158250
,但存在不同的其他人。
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e663"),
"worker_id" : "158250",
"employer" : "139998",
"start_date" : ISODate("2012-02-15T01:00:00.000+01:00"),
"end_date" : ISODate("2012-04-17T02:00:00.000+02:00"),
"ord_id" : 484
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e665"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2012-10-17T02:00:00.000+02:00"),
"end_date" : ISODate("2012-11-15T01:00:00.000+01:00"),
"ord_id" : 486
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e667"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2013-06-01T02:00:00.000+02:00"),
"end_date" : ISODate("2013-09-30T02:00:00.000+02:00"),
"ord_id" : 488
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e666"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2013-02-01T01:00:00.000+01:00"),
"end_date" : ISODate("2013-05-31T02:00:00.000+02:00"),
"ord_id" : 487
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e664"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2012-03-12T01:00:00.000+01:00"),
"end_date" : ISODate("2012-05-12T02:00:00.000+02:00"),
"ord_id" : 485
},
{
"_id" : ObjectId("5f33a6bafdb40e7c44a4e668"),
"worker_id" : "158250",
"employer" : "5794265",
"start_date" : ISODate("2015-06-01T02:00:00.000+02:00"),
"end_date" : ISODate("2015-11-30T01:00:00.000+01:00"),
"ord_id" : 489
}
我想在每个文档中添加一个名为 'next' 的新字段,它引用以下基于 ord_id
的合同。为此,我执行了以下命令:
db.mycollection.aggregate([
{ $sort: { ord_id: 1 } },
{
$lookup:
{
from: "mycollection",
let: { id_lav: "$worker_id", curr_ord_id: "$ord_id" }, // 'curr_' is for current
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$worker_id", "$$id_lav" ] },
{ $gt: [ "$ord_id", "$$curr_ord_id" ] }
]
}
}
}, { $limit: 1 }
],
as: "next"
}
},
{ $unwind: { path: "$next", preserveNullAndEmptyArrays: true} },
{ $out: "mycollection" } ],
{ allowDiskUse: true } );
但是,我肯定遗漏了一些东西。事实上,某些文档的 'next' 字段与后面的有效字段不匹配。例如,'ord_id' 等于 484 的文档结果被 linked 到 'ord_id' 等于 486 而不是 485 的文档。相反,其他文档被 linked适当地。为了解决这个问题,我以这种方式稍微修改了以前的代码:
db.mycollection.aggregate([
{ $sort: { ord_id: 1 } },
{
$lookup:
{
from: "mycollection",
let: { id_lav: "$worker_id", curr_ord_id: "$ord_id" }, // 'curr_' is for current
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$worker_id", "$$id_lav" ] },
{ $gt: [ "$ord_id", "$$curr_ord_id" ] },
{ $eq: [ { $subtract: [ "$ord_id", "$$curr_ord_id" ] }, 1 ] },
{ $or: [
{ $eq: [ "$worker_id", "$$id_lav" ] },
{ $gt: [ "$ord_id", "$$curr_ord_id" ] }
] }
]
}
}
}, { $limit: 1 }
],
as: "next"
}
},
{ $unwind: { path: "$next", preserveNullAndEmptyArrays: true} },
{ $out: "mycollection" } ],
{ allowDiskUse: true } );
我完全不明白为什么第一个命令没有给出所需的输出。尽管如此,我相信有更好的方法来解决这个问题。任何建议表示赞赏。提前致谢!
您的第一个管道非常接近。主要问题是你必须在 $lookup
中 $sort
,你现在拥有的 $sort
是多余的(你可以保留它,这样新集合将在 [=14= 之后排序) ] 因此,如果您将来 运行 在同一更新中 $sort
将不再需要)。
db.mycollection.aggregate([
{
$lookup: {
from: "mycollection",
let: {
id_lav: "$worker_id",
curr_ord_id: "$ord_id"
},
/** 'curr_' is for current*/
pipeline: [
{
$sort: {
ord_id: 1
}
},
{
$match: {
$expr: {
$and: [
{
$eq: [
"$worker_id",
"$$id_lav"
]
},
{
$gt: [
"$ord_id",
"$$curr_ord_id"
]
}
]
}
}
},
{
$limit: 1
}
],
as: "next"
}
},
{
$unwind: {
path: "$next",
preserveNullAndEmptyArrays: true
}
},
{ $unwind: { path: "$next", preserveNullAndEmptyArrays: true} },
{ $out: "mycollection" }
],
{
allowDiskUse: true
})