我正在尝试比较两个集合中的不同文档 以下是示例, Mongodb版本:4.0 , ORM:猫鼬
**col1: Has one new document**
{ "id" : 200001, "mobileNo" : #######001 }
{ "id" : 200002, "mobileNo" : #######002 } //mobileNo may not be unique.
{ "id" : 200003, "mobileNo" : #######002 }
{ "id" : 200004, "mobileNo" : #######004 }
**col2:**
{ "id" : 200001, "mobileNo" : #######001 }
{ "id" : 200002, "mobileNo" : #######002 }
{ "id" : 200003, "mobileNo" : #######003 }
现在,我要将文档{ "id" : 200004, "mobileNo" : #######004 }
从col1
插入到col2
即;不匹配的文件。
这是我到目前为止尝试过的:
const col1= await Col1.find({}, { mobileNo: 1,id: 1, _id: 0 })
col1.forEach(async function (col1docs) {
let col2doc = await Col2.find({ mobileNo: { $ne: col1docs.mobileNo},
id:{$ne:col1docs.id} }, { mobileNo: 1, _id: 0, id: 1 })
if (!(col2doc)) {
Col2.insertMany(col1docs);
}
});
我也尝试用$ eq代替$ ne,但是我都没有得到不匹配的文档,也没有插入它们。有什么建议??? id + phoneNo的组合是唯一的
答案 0 :(得分:1)
我想说,而不是执行两次.find()
调用加上迭代,然后再进行第三次调用来写入数据,请尝试以下查询:
db.col1.aggregate([
{
$lookup: {
from: "col2",
let: { id: "$id", mobileNo: "$mobileNo" },
pipeline: [
{
$match: { $expr: { $and: [ { $eq: [ "$id", "$$id" ] }, { $gte: [ "$mobileNo", "$$mobileNo" ] } ] } }
},
{ $project: { _id: 1 } } // limiting to `_id` as we don't need entire doc of `col2` - just need to see whether a ref exists or not
],
as: "data"
}
},
{ $match: { data: [] } // Filtering leaves docs in `col1` which has no match in `col2`
},
{ $project: { data: 0, _id: 0 } }
])
测试: mongoplayground
详细信息::从以上查询中,您可以利用在$lookup中指定条件来从col1
获取在col2
中具有引用的文档。假设$lookup
将在col1
的每个文档上运行-因此,id & mobileNo
中来自当前文档的col1
的唯一组合在col2
中具有一个匹配项,然后{ {1}}个文档的col2
将被推送到_id
数组中,最后我们从data
中得到的结果是col1
,表示找不到与这些{ {1}}个文档。现在,您可以使用data: []
将所有返回的文档写入col1
。实际上,您可以在MongoDB版本> col2
上使用$merge来完成全部操作,而无需第二次写调用(.insertMany()
)。
对于您在MongoDB版本上使用的场景> 4.2
,类似的操作会将文档合并到第二个集合中:
.insertMany()
注意::如果必须定期执行此操作-无论您如何执行,都应尽量减少所处理的数据,也许要保留一个时间字段,然后可以使用该字段来首先过滤文档并执行此工作,或者您也可以利用4.2
来表示我们已在上次运行中对所有这些文档进行了处理,我们需要从此文档开始-这将大大帮助您减少数据待开发。另外,别忘了维护索引。