我有一个对象数组,如下所示:
{ type: 'foo', value : 2, hashedIdentifier : ASDZXC, createdAt : '2022-02-27T14:17:44.860+00:00' }
我想将它们批量插入MongoDB集合中。我的业务逻辑要求在7天内不创建2个相同的对象。为此,我使用hashedIdentifier
字段来查找重复项,其中createdAt
是$gte
";7天前";,从数组中筛选重复项,然后插入数组中剩余的项。
这是两个不同的DB查询,我正在寻找一个更为封闭和原子化的查询。
我在看updateMany的upstart,但没能搞清楚。
有没有一种方法可以批量插入所有数组对象,只插入那些与上述约束(标识符+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"}
}
])
正如你在这个操场上看到的例子。
首先,我们按hashedIdentifier
对现有文档进行分组,因为我们只对最新的现有日期感兴趣。然后,我们保留与我们测试插入的文档匹配的相关文档,并将所有文档分组到一个文档中。下一步是使用$addFields
添加所有新项目,并将其添加到$unwind
中,这样它们将是单独的文档。现在,我们只需要为每个新项目、现有项目(如果有的话(进行匹配,并测试时差条件(604800000ms(。与此条件匹配的文档可以作为新的已验证文档$merge
d返回集合。