仅在满足指定条件时批量插入

Bulk insert only when specified condition is met

我有一组对象,如下所示:

{ type: 'foo', value : 2, hashedIdentifier : ASDZXC, createdAt : '2022-02-27T14:17:44.860+00:00' }

我想将它们批量插入到 MongoDB 集合中。 我的业务逻辑要求在 7 天内不能创建 2 个相同的对象。为此,我使用 hashedIdentifier 字段查找重复项,其中 createdAt$gte“7 天前”,从数组中过滤重复项,然后插入数组中剩余的内容。

这是 2 个不同的数据库查询,我正在寻找更封闭和原子化的东西。

我正在查看带有 upsert 的 updateMany,但无法解决这个问题。

有没有办法批量插入所有数组对象,只插入那些与上述约束(标识符+createdAt范围)不冲突的对象?

一种方法是使用带有 $merge 的聚合管道。例如:

db.collection.aggregate([
  {
    $group: {
      _id: "$hashedIdentifier",
      latestExisting: {
        $max: "$createdAt"
      }
    }
  },
  {
    $match: {
      _id: {
        $in: [
          "ASDZXC",
          "TSSGKE",
          "SDFKAR"
        ]
      }
    }
  },
  {
    $group: {
      _id: 0,
      existing: {
        $push: {
          hashedIdentifier: "$_id",
          latestExisting: "$latestExisting"
        }
      }
    }
  },
  {
    $addFields: {
      newItems: [
        {
          type: "foo",
          value: 2,
          hashedIdentifier: "ASDZXC",
          createdAt: ISODate("2022-03-06T14:18:44.860+00:00")
        },
        {
          type: "bar",
          value: 3,
          hashedIdentifier: "TSSGKE",
          createdAt: ISODate("2022-03-06T15:17:44.860+00:00")
        },
        {
          type: "newOne",
          value: 9,
          hashedIdentifier: "SDFKAR",
          createdAt: ISODate("2022-03-06T15:17:44.860+00:00")
        }
      ]
    }
  },
  {
    $unwind: "$newItems"
  },
  {
    $project: {
      existing: {
        $filter: {
          input: "$existing",
          as: "item",
          cond: {
            $eq: [
              "$$item.hashedIdentifier",
              "$newItems.hashedIdentifier"
            ]
          }
        }
      },
      newItems: 1,
      latestExisting: 1
    }
  },
  {
    $project: {
      existing: {$arrayElemAt: ["$existing", 0]},
      newItem: "$newItems"
    }
  },
  {
    $project: {
      delta: {
        $subtract: [
          "$newItem.createdAt",
          "$existing.latestExisting"
        ]
      },
      latestExisting: 1,
      newItem: 1
    }
  },
  {
    $match: {
      $or: [{ delta: {$gte: 604800000}}, {delta: null}]
    }
  },
  {
    $replaceRoot: {newRoot: "$newItem"}
  },
  {
    $merge: {into: "collection"}
  }
])

如您所见playground example

首先,我们按 hashedIdentifier 对现有文档进行分组,因为我们只对最新的现有日期感兴趣。然后我们保留与我们测试插入的文档匹配的相关文档,并将它们全部分组到一个文档中。下一步是使用 $addFields 添加所有新项目,并将其添加到 $unwind,因此它们将是单独的文档。现在我们只需要匹配每个新项目,如果有现有项目,并测试时间差条件(604800000 毫秒)。符合此条件的文档可以 $merge 作为新的经过验证的文档返回到集合中。