来自Mongo的新人的快速提问。
我有一组文件(简化)如下:
{"_id":<objectID>, "name":"fakeName", "seeds":[1231,2341,0842,1341,3451, ...]}
我真正需要的是一个$ pop,从我的种子列表中弹出2或3个项目,但$ pop目前仅适用于one项目,所以我试图寻找另一种方式来完成同样的事情。
我看到的第一件事是使用空的&#34;每个&#34;来执行$ push / $ each / $ slice,如:
update: { $push: { order: { $each: [ ], $slice: ?}}}
这里的问题是我不知道我想要新切片的确切时间(我希望它是&#34;当前大小 - 我弹出的种子数量#34;)。如果$ slice修饰符像$ slice投影一样工作,这很容易,我可以做$ slice:[#of seeds,]但是它没有这样做,所以它不起作用。
我接下来要看的是获取数组的一侧并将其用作$ slice的输入,如:
update: { $push: { seeds: { $each: [ ], $slice: {$subtract: [{$size:"$seeds"}, <number of seeds to pop>]}}}}
但是Mongo告诉我&$ 34; $ slice的值必须是数值而不是Object&#34;,所以显然$ subtract的结果是Object而不是数字。
然后我试着看看能否&#34;删除&#34;数组中的项目基于带有$ limit的空查询,但显然限制会在管道中稍后应用,因此我无法设法使其工作。
还有其他建议吗,或者我运气不好,需要回到绘图板上?
非常感谢您的帮助/输入。
答案 0 :(得分:1)
MongoDB目前没有任何方法可以在单个更新语句中引用现有的字段值。唯一的例外是$inc
和$mul
之类的运算符,它们可以对当前值起作用并根据设定规则对其进行更改。
这部分是由于&#34;措辞&#34;的兼容性。对多个文件采取行动的行动,无论是否属实。但你要求的是一些&#34;变量&#34;允许&#34;长度&#34;要测试和使用的数组,如输入参数&#34;另一种方法。这不受支持。
所以你能做的最好就是阅读文档内容并在代码中测试数组的长度,然后在你第一次推测时执行$slice
更新,或者你也可以使用聚合框架来计算&#34;可能的长度&#34;数组(假设有很多重复),然后工作&#34;多&#34;更新符合条件的文档,当然假设您要对多个文档执行此操作。
第一种形式:
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();
注意到在这两种情况下都有一些逻辑要考虑数组的长度,以免“#34;空”&#34;它们,或产生不希望的$slice
操作。
另一种可能的替代方法是在查询中使用$slice
的投影形式来获取最后n
个元素,然后$pull
来自数组的匹配元素。当然,用于此类操作的标识符必须是&#34;唯一的&#34;,但它是确保唯一性的有效案例。
因此,无论您的情况如何,如果不事先了解要修改的文档的当前状态,则无法在单个更新语句中执行此操作。不同的列表虽然为您提供了接近&#34;模拟&#34;这虽然不在一个声明中。