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

标签 javascript mongodb mongodb-query

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/

相关文章:

javascript - 查找JS数组中最大的数字并返回变量名

javascript - 使用 HTML/Javascript 访问动态创建的 div 中的元素

mongodb - 如果事务中止,则在数据库中创建记录(MongoDB.Driver 和 .NETCore)

mongodb - Node.js 和 Mongodb - TypeError : undefined is not a function

mongodb - 如何使用 MongoDB 中的另一个数字字段更新数字字段

node.js - MongoDB:连接多个数组

JavaScript try catch 语句

javascript - 使用 CSS 过渡将元素设置为显示和加宽

MongoDB:导入大文件时 mongoimport 失去连接

javascript - MongoDB $cmp(聚合)给出错误结果