仅在满足指定条件时批量插入
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范围)不冲突的对象?
- 唯一(或复合唯一)索引在这里对我没有用,因为我确实想在时间范围(7 天)过去后启用重复项的创建。
- 集合对象的 TTL 也是不可能的,因为我想永远保留它们。
一种方法是使用带有 $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
作为新的经过验证的文档返回到集合中。
我有一组对象,如下所示:
{ 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范围)不冲突的对象?
- 唯一(或复合唯一)索引在这里对我没有用,因为我确实想在时间范围(7 天)过去后启用重复项的创建。
- 集合对象的 TTL 也是不可能的,因为我想永远保留它们。
一种方法是使用带有 $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
作为新的经过验证的文档返回到集合中。