MongoDB将两个集合与不匹配的文档合并

时间:2020-04-30 13:11:19

标签: node.js mongodb mongoose mongodb-query

我正在尝试比较两个集合中的不同文档 以下是示例, 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的组合是唯一的

1 个答案:

答案 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来表示我们已在上次运行中对所有这些文档进行了处理,我们需要从此文档开始-这将大大帮助您减少数据待开发。另外,别忘了维护索引。