gpt4 book ai didi

javascript - 我如何在 MongoDB 中伪造一个多项目 $pop?

转载 作者:可可西里 更新时间:2023-11-01 10:43:16 26 4
gpt4 key购买 nike

Mongo 新手的快速提问。

我有一组文档(简化)如下所示:

{"_id":<objectID>, "name":"fakeName", "seeds":[1231,2341,0842,1341,3451, ...]}

我真正需要的是一个 $pop,它可以从我的种子列表中弹出 2 或 3 个项目,但 $pop 目前只适用于 one项目,所以我试图寻找另一种方法来完成同样的事情。

我首先看到的是用一个空的“each”做 $push/$each/$slice,比如:

update: { $push: { order: { $each: [ ], $slice: ?}}}

这里的问题是我不知道我希望我的新切片到底有多长(我希望它是“当前大小 - 我弹出的种子数”)。如果 $slice 修饰符像 $slice 投影一样工作,这会很容易,我可以只做 $slice: [ #of seeds, ],但事实并非如此,所以那行不通。

接下来我要看的是获取数组的边并将其用作 $slice 的输入,例如:

update: { $push: { seeds: { $each: [ ], $slice: {$subtract: [{$size:"$seeds"}, <number of seeds to pop>]}}}}

但是 Mongo 告诉我“$slice 的值必须是数值而不是对象”,所以显然 $subtract 的结果是对象而不是数字。

然后我尝试看看我是否可以基于带有 $limit 的空查询从数组中“删除”项目,但显然 limit 稍后会在管道中应用,所以我无法完成这项工作。

还有其他建议吗?还是我运气不好,需要重新开始?

非常感谢您的帮助/输入。

最佳答案

MongoDB 目前没有任何方法可以在单个更新语句中引用字段的现有值。唯一的异常(exception)是诸如 $inc$mul 之类的运算符,它们可以作用于当前值并根据设定的规则对其进行更改。

这部分是由于对多个文档进行操作的“措辞”的兼容性,无论是否是这种情况。但是您要求的是一些“可变”操作,允许测试数组的“长度”并将其用作另一种方法的“输入参数”。这是不支持的。

所以你能做的最好的就是阅读文档内容并在代码中测试数组的长度,然后执行$slice。按照您最初的推测进行更新,或者您可以使用聚合框架计算出数组的“可能长度”(假设有很多重复),然后对符合条件的文档进行“多”更新,当然假设您想对多个文档执行此操作。

第一种形式:

var bulk = db.collection.initializeOrderedBulkOp();
var count = 0;

db.collection.find().forEach(function(doc) {
if ( doc.order.length > 2 ) {
bulk.find({ "_id": doc._id })
.updateOne({
"$push": {
"order": { "$each": [], "$slice": doc.order.length - 2 }
}
});
count ++;
}

if ( (count % 1000) == 0 && ( count > 1 ) ) {
bulk.execute();
bulk = db.collection.initializeOrderedBulkOp();
}
});

if ( count % 1000 != 0 )
bulk = db.collection.initializeOrderedBulkOp();

第二种形式:

var bulk = db.collection.initializeOrderedBulkOp();
var count = 0;

db.collection.aggregate([
{ "$group": { "_id": { "$size": "$order" } }},
{ "$match": { "$_id": { "$gt": 2 } }}
]).forEach(function(doc) {

bulk.find({ "order": { "$size": doc._id } })
.update(
"$push": {
"order": { "$each": [], "$slice": doc._id - 2 }
}
});
count ++;

if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.collection.initializeOrderedBulkOp();
}
});

if ( count % 1000 != 0 )
bulk = db.collection.initializeOrderedBulkOp();

请注意,在这两种情况下,都有一些逻辑考虑数组的长度,以免“清空”它们或产生不需要的 $slice 操作。

另一种可能的替代方法是使用 $slice 的投影形式在查询中获取最后的 n 元素,然后是 $pull数组中的匹配元素。当然,用于此类操作的标识符必须是“唯一的”,但这是确保唯一性的有效情况。

因此,无论您遇到什么情况,如果不事先了解要修改的文档的当前状态,就不能在单个更新语句中执行此操作。虽然不同的列表为您提供了“模拟”此方法的方法,但不是在一个单独的语句中。

关于javascript - 我如何在 MongoDB 中伪造一个多项目 $pop?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29122673/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com