【问题标题】:How can I $addToSet an object to an array and $sort too using MongoDB?如何使用 MongoDB 将对象 $addToSet 到数组和 $sort 中?
【发布时间】:2015-07-11 22:59:24
【问题描述】:

我需要将一个对象添加到 MongoDB 集合文档中的数组中,插入后我需要确保所有数组的元素都按其属性之一排序。

因为我需要数组中的对象是唯一的,所以我使用 $addToSet 而不是 $push。这是我正在尝试的一个示例:

db.perros.update(
    {name: "Risas"}, 
    {
        $addToSet: {propiedades: {name: "cola", cantidad: 1}}, 
        $push: { propiedades: { $each: [ ], $sort: {cantidad: -1} }}
    });

但是这将失败并出现以下 Mongo 错误:

WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 16837,
        "errmsg" : "Cannot update 'propiedades' and 'propiedades' at the same time"
    }
})

当您考虑 sets 时,这一点很明显,但是 $push 操作甚至不关心数组内部的内容......如何在不使用 $push 的情况下实现这一点?

【问题讨论】:

  • 它目前无法与 $push 一起使用,对吧?不应该只是我 $addToSet :{}, $sort: {propiedades: {cantidad: -1}} 或类似的东西吗?
  • 我不懂你
  • @ChadF 只有$each 修饰符对$addToSet 有效。不能使用 $sort 修饰符,因为 MongoDB 不考虑对“集合”进行排序。这就是为什么这里的 OP 尝试了这种方法并因此发现了无法一次将多个更新操作应用于同一属性路径的错误。当然,还有其他方法可以做到这一点。

标签: arrays mongodb


【解决方案1】:

通过正确识别需要执行的操作,您参与其中。但当然 $sort 不是 $addToSet 的有效修饰符,因为 MongoDB 的口头禅是“不认为集合是有序的”

$addToSet 不保证修改集中元素的特定顺序。

错误指出的另一个问题是,您不能同时在同一路径上使用多个更新运算符(例如 $addToSet$push )指向属性。事实上,不同更新操作符的执行没有“顺序”,因此它们不能保证$addToSet 出现在$push 之前。事实上,它们很可能是并行执行的,这就是错误的原因,并且这是不允许的。

答案当然是“两个”更新语句。一个用于$addToSet,另一个用于通过$each“推送”一个空数组来应用$sort

但由于我们真的不想“等待”每次更新完成,这就是“批量”操作 API 的用途。因此,您可以在 one 发送中将两个指令发送到服务器并获得 one 响应:

var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({ "name": "Risas" }).update({ 
   "$addToSet": { 
       "propiedades": { "name": "cola", "cantidad": 1 }
   }
});
bulk.find({ "name": "Risas" }).update({ 
   "$push": { 
       "propiedades": { 
           "$each": [ ], "$sort": { "cantidad": -1 } 
        }
   }
});
bulk.execute();

所以这仍然只是对服务器的一个请求和一个响应。它仍然是“两个”操作,但某些线程获取更新的临时状态的开销和可能性可以忽略不计。

有一种替代方法是将“集合检测”逻辑移动到更新语句的.find() 部分,然后只应用$push 将成员添加到“集合" 尚不存在:

var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({ 
    "name": "Risas", 
    "propiedades": { 
        "$not": { "$elemMatch": { "name": "cola", "cantidad": 1 } } 
    } 
}).update({ 
   "$push": { 
       "propiedades": { 
           "$each": [{ "name": "cola", "cantidad": 1 }], "$sort": { "cantidad": -1 } 
        }
   }
});
bulk.execute();

当然,复杂之处在于,如果您在此处添加“多个”数组元素,则需要将这些 $not$elemMacth 测试包装在 $and 条件中,然后如果其中“只有一个”元素有效,则不能单独添加。

您可以“首先”使用“多个”项目“尝试”这种操作,但是您应该使用与上述相同的逻辑对每个单独的数组元素进行“后备”执行“测试”每一个“推动”的可能性。

所以$addToSet 通过多个数组条目使第二部分变得容易。对于一个条目,只需“查询”和$push 非常简单,对于不止一个条目,它可能是使用带有$addToSet$push 的“第一个”模式的更短路径来“排序”结果因为应用第二种模式意味着无论如何都要进行多次更新测试。

【讨论】:

    猜你喜欢
    • 2019-02-17
    • 2016-02-08
    • 2017-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-08
    相关资源
    最近更新 更多