【问题标题】:How to get the index of an array element in older versions on Mongodb?如何在 Mongodb 的旧版本中获取数组元素的索引?
【发布时间】:2020-04-05 10:31:59
【问题描述】:

我使用的是 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 布尔值的查询/更新。

编辑2: 这是我阅读答案后的功能:

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 的 triggered 值当前为 false。此函数运行时,传入的triggered 值为true,但它不会更新文档。有什么建议吗?

【问题讨论】:

  • 您不必为了更新特定对象中的特定字段而获取数组中对象的索引,您可以使用 mongoDB 中的位置运算符来完成,请给我们示例文档&需要o / p有人可以帮助您查询!
  • 我已经用示例文档更新了我的答案,以及我想要完成的工作。谢谢。

标签: arrays node.js mongodb indexing


【解决方案1】:

实际上,您正在以错误的方式解决问题。数组本质上是动态的。 如果您的应用程序处于活动状态并且正在发生交互,则无法确定您正在更新的索引在您从查询中获取时是否完全相同。因为某些人可能已从中插入或删除文档。

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

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/

这样你就不用依赖索引直接更新你需要的对象了。

【讨论】:

  • 我在上面更新了我的问题。我尝试了updateupdateOne 都没有任何效果。
【解决方案2】:

请尝试:

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

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

参考: mongoDB $(update)

【讨论】:

  • 我在上面更新了我的问题。什么都没发生。为了安全起见,我尝试使用 Mongo 的 ObjectID,但没有效果。
  • @Brian : 你检查action._iddeviceId 的类型是否与实际文档中的_id 的类型和device_id 的类型匹配!!请尝试使用相同过滤器的查找方法,如果是,请检查您是否收到任何文档,然后让我们看看更新是否有任何问题 - 如果类型匹配,则不应该有任何问题..
  • 我认为你是对的。当我使用仅包括以下内容的过滤器查询进行查找时:{_id: action._id} 它会找到正确的文档,但是当我添加后半部分时:{_id: action._id, 'history.device_id': device._id} 然后我没有返回任何文档。
  • @Brian : 如果类型不匹配,那么我们需要将device._id 设为ObjectId()(转换为数据库中存在的任何类型),请检查mongoose :: stackoverflow.com/questions/6578178/…或者这个mongoDB :: stackoverflow.com/questions/7825700/…
  • 是的,这就是问题所在。在数据库中,有些 device_ids 是 ObjectID,有些是 string.... 很烦人。感谢您的帮助!
猜你喜欢
  • 2016-05-08
  • 1970-01-01
  • 2021-08-17
  • 2016-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-15
  • 1970-01-01
相关资源
最近更新 更多