繁体   English   中英

如何在Mongodb上的旧版本中获取数组元素的索引?

[英]How to get the index of an array element in older versions on Mongodb?

我正在使用 Mongo 版本 2.2.33。 这是一个大型项目,主要是遗留代码,更新内容不取决于我。 如果我有一个更新版本的 Mongo,我会使用 $indexOfArray,但既然我不能,我怎么能达到同样的目的呢?

这是我在意识到我们使用的是哪个版本的 mongo 之前编写的代码:

exports.getActionHistoryIndex = function (historyArray, deviceId, cb) {
  db.actions.aggregate({$indexOfArray: {historyArray, deviceId}}, function (err, index) {
    if (err) {
      return cb(err)
    } else {
      return cb(null, index)
    }
  })
}

当我调用该函数时,如下所示:

actionRepo.getActionHistoryIndex(action.history, device._id, (err, res) => {
    if (err) console.log(err)
    console.log(res)
  })

我收到此错误,因为 $indexOfArray 在 3.8 之后可用,我认为:

 name: 'MongoError',
  message: 'Unrecognized pipeline stage name: \'$indexOfArray\'',
  ok: 0,
  errmsg: 'Unrecognized pipeline stage name: \'$indexOfArray\'',
  code: 40324,
  codeName: 'Location40324' }
undefined

有没有一种简单的方法来实现这一目标? 基本上,问题是我有一个 db 集合,其中包含一个包含对象的数组。 我需要能够在数组中的对象中搜索某个_id ,然后编辑同一对象中的另一个属性。 所以我的计划是获取正确对象的索引,然后使用索引更新需要更改的属性。

任何帮助表示赞赏。

编辑:这是来自action集合的示例文档。

_id : ObjectId('ABC')
history: [Array]
  0: {Object}
    device_id: ObjectId("123")
    triggered: false
  1: {Object}
    device_id: ObjectId("456")
    triggered: true

收到用户输入后,我需要更改triggered布尔值。 我有操作文档 ObjectId,我有对应于history数组中不同对象的 device_id。 所以我正在寻找一个查询/更新,它将允许我更改triggered布尔值。

EDIT2:这是我阅读答案后的功能:

exports.updateHistory = function (action, deviceId, triggered, cb) {
  console.log(action._id + '  ||  action._id')
  console.log(deviceId + '  ||  deviceId')
  console.log(triggered + '  ||  triggered')
  db.actions.updateOne(
    {_id: action._id, 'history.device_id': deviceId},
    {$set: { 'history.$.triggered': triggered }},
    {w: 1},
    function (err, results) {
      if (err) {
        return cb(err)
      }
      return cb(null, results)
    })
}

所有日志语句都是正确的,我没有收到任何错误,但我的文档根本没有更改。 对于三个不同的action文档,此函数被调用 3 次。 所有 3 的triggered值当前为 false。 此函数运行时,传入的triggered值为true ,但不会更新文档。 有什么建议?

实际上,您以错误的方式处理问题。 数组本质上是动态的。 如果您的应用程序是实时的并且正在发生交互,那么当您从查询中获取它时,无法保证您正在更新的索引将完全相同。因为有些人可能已经插入或从中删除了文档。

至于你的问题,你可以这样做:

db.collection.update({"_id" : <parent_id>, "history.device_id" : "<you-passed-device-id>"},  
                     {$set : {history.$.triggered: false} },
                     false , 
                    true);

不确定您的 mongo 服务器版本中是否引入了https://docs.mongodb.com/manual/reference/operator/update/positional/

这样您就不会依赖于索引并直接更新您需要的对象。

请尝试 :

db.yourCollectionName.updateOne({"_id" : ObjectId('ABC'),
'history.device_id':ObjectId("123")}, { $set: { "history.$.triggered" : false } })

从上面我们使用.updateOne()因为我们只是通过传递唯一的_id :ObjectId('ABC')更新特定对象。 传递这个也有利于使用索引键匹配准确的一个文档,并且它确保您实际上正在更改正确的动作文档 - 以防万一相同的device_id存在于多个动作文档的历史数组中!! $运算符实际上将更新传入过滤器的数组中的第一个匹配对象/元素,否则如果您需要修改与过滤器查询匹配的所有元素,那么您可以在 >=3.6 版本上尝试$[]

参考: mongoDB $(更新)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM