简体   繁体   English

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

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

I am using Mongo version 2.2.33.我正在使用 Mongo 版本 2.2.33。 This is for a large project, mostly legacy code, and updating things is not up to me.这是一个大型项目,主要是遗留代码,更新内容不取决于我。 If I had a newer version of Mongo I would use $indexOfArray, but since I can't, how can I achieve the same thing?如果我有一个更新版本的 Mongo,我会使用 $indexOfArray,但既然我不能,我怎么能达到同样的目的呢?

This is the code I wrote before I realized what version of mongo we were using:这是我在意识到我们使用的是哪个版本的 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)
    }
  })
}

When I call the function, like this:当我调用该函数时,如下所示:

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

I get this error, because $indexOfArray is onlay available after 3.8, I think:我收到此错误,因为 $indexOfArray 在 3.8 之后可用,我认为:

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

Is there an ease way to achieve this?有没有一种简单的方法来实现这一目标? Basically, the problem is that I have a db collection with an array that contains objects.基本上,问题是我有一个 db 集合,其中包含一个包含对象的数组。 I need to be able to search among the objects in the array for a certain _id and then edit another attribute in the same object.我需要能够在数组中的对象中搜索某个_id ,然后编辑同一对象中的另一个属性。 So my plan is to get the index of the correct object, and then use the index to update the attribute that needs to be changed.所以我的计划是获取正确对象的索引,然后使用索引更新需要更改的属性。

Any help is appreciated.任何帮助表示赞赏。

EDIT: This is a sample document from the action collection.编辑:这是来自action集合的示例文档。

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

Upon receiving user input, I need to change the triggered boolean.收到用户输入后,我需要更改triggered布尔值。 I have the action document ObjectId and I have the device_id that corresponds to the different objects in the history array.我有操作文档 ObjectId,我有对应于history数组中不同对象的 device_id。 So I'm looking for a query/update that will allow me to change the triggered boolean.所以我正在寻找一个查询/更新,它将允许我更改triggered布尔值。

EDIT2: This is the function I have after reading answers: 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)
    })
}

All of the log statements are correct, and I don't get any errors, but my documents aren't changed at all.所有日志语句都是正确的,我没有收到任何错误,但我的文档根本没有更改。 This function gets called three times for three different action documents.对于三个不同的action文档,此函数被调用 3 次。 The triggered value for all 3 is currently false.所有 3 的triggered值当前为 false。 When this function runs, the triggered value passed in is true , but it doesn't update the document.此函数运行时,传入的triggered值为true ,但不会更新文档。 Any suggestions?有什么建议?

Actually You are approaching the problem in wrong way.实际上,您以错误的方式处理问题。 Array is dynamic in nature.数组本质上是动态的。 If your application is live and interactions are happening than there's no surety that the index you are updating is going to be the exact same while you get it from query.As some one might have document inserted or removed from it.如果您的应用程序是实时的并且正在发生交互,那么当您从查询中获取它时,无法保证您正在更新的索引将完全相同。因为有些人可能已经插入或从中删除了文档。

As for your problem you can do it like:至于你的问题,你可以这样做:

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

Not sure if https://docs.mongodb.com/manual/reference/operator/update/positional/ has been introduced in your version of mongo server.不确定您的 mongo 服务器版本中是否引入了https://docs.mongodb.com/manual/reference/operator/update/positional/

This way you are not dependent on the index and directly updating the object of you need.这样您就不会依赖于索引并直接更新您需要的对象。

Please try :请尝试 :

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

From the above we're using .updateOne() as we're just updating a specific object by passing unique _id :ObjectId('ABC') .从上面我们使用.updateOne()因为我们只是通过传递唯一的_id :ObjectId('ABC')更新特定对象。 Also passing this is beneficial in order to match the exact one document using indexed key & also it ensures you're actually changing proper action document - just in case same device_id exists in history array of multiple action documents !!传递这个也有利于使用索引键匹配准确的一个文档,并且它确保您实际上正在更改正确的动作文档 - 以防万一相同的device_id存在于多个动作文档的历史数组中!! $ operator will actually update the first matching object/element in an array wrt passed in filter, otherwise if you need all elements which matches to filter query to be modified then you can try $[] on >=3.6 versions. $运算符实际上将更新传入过滤器的数组中的第一个匹配对象/元素,否则如果您需要修改与过滤器查询匹配的所有元素,那么您可以在 >=3.6 版本上尝试$[]

Ref : mongoDB $(update)参考: mongoDB $(更新)

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

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