【问题标题】:MongoDB modify the array of objects field by element number without findAndModify or update queryMongoDB 通过元素编号修改对象字段的数组,无需 findAndModify 或更新查询
【发布时间】:2020-11-13 19:56:15
【问题描述】:

我在更新/修改 Mongoose 嵌入文档时遇到问题。

我的函数通过 EachASync 光标逐个遍历集合中的每个文档:

//inside async function
.EachASync(async MongoDoc => { //<= Mongo Document type, not lean!
  //other logic modifiying other fields

  const names = ['name1'] //it could be multiple values

  
  for (const element of names ) {
    //findIndex in MongoDoc.filter.realms <= array of objects
    const index = MongoDoc.filter.realms.findIndex(realm => realm.name === element)
    //I want to update the specific object property 'time' inside array by index
    MongoDoc.filter.realms[index].time = Date.now()
  }
  await MongoDoc.save()
}

其实我是在修改整个文档,但是我想更新具体的嵌套对象字段,里面包含对象字段的数组。

所选字段的架构:

// Schema
{
  _id: MongoID,
  //many other fields,
  filter: { // <= parent field
    realm: [{ // <= parent object
      name: String,
      time: Number, //the value that I want to update by index
    }]
  }
}

示例

{
  _id: 1,
  filter: {
    realms: [
      {
        name: "name1", 
        time: 1, //modify this values via it's index number 
        // in this case it's 0
        // via MongoDoc.filter.realms, without updateOne or findAndUpdate
      },
      {
        name: "name2",
        time: 2,
      },
      {
        name: "name3",
        time: 3,
      }
    ]
  }
}

所以问题是:如何适当地实现我的结果?不使用findAndUpdateupdateOne?根据this article 的说法,这是有可能的。

另外,最佳解决方案是什么?通过索引更新必要的对象值?喜欢:

MongoDoc.filter.realms[index].time = Date.now()

或者通过复制/改变原始对象来重建整个对象数组?

【问题讨论】:

  • 你能发布一个文档示例和预期输出吗?
  • @J.F .是的,没问题,会在几分钟内更新。我想在 MongoPlayground 上发帖,但不幸的是,这不是他们的用例
  • 所以我假设你不想使用:"$set": { "filter.realms.0.time": newValue }。但是,因为您不想要或者您认为您不能在查询中设置"filter.realms."+index+".time"
  • @J.F.我想使用"filter.realms."+index+".time",但我不确定如何正确使用。另外,如果MongoDoc.filter.realms.$set() 有效,我也想使用它。我没有这方面的经验,所以这就是我问这个的原因。关于这个案例,我也没有找到任何关于 SO 的信息。所有示例都是关于findAndModifyupdate 查询,而不是修改现有的Mongoose 文档。

标签: javascript node.js mongodb mongoose


【解决方案1】:

我看过你的代码,当你想按索引更新时,我认为你错了。

你认为你需要索引,因为你知道使用findIndex() 的对象在哪里'name1'。但这不是一个好方法。

您的代码循环遍历整个集合,逐个文档,并查找name 字段为“name1”、“name2”或“name3”的数组索引。然后用实际日期更新time 值,对吧?

您可以通过简单的mongo 查询来完成此操作,无需循环或 JS 函数。检查this example

db.collection.update({
  "_id": 1,
  
},
{
  "$set": {
    "filter.realms.$[element].time": new Date()
  }
},
{
  "arrayFilters": [
    {
      "$or": [
        {
          "element.name": "name1"
        },
        {
          "element.name": "name2"
        },
        {
          "element.name": "name3"
        }
      ]
    }
  ]
})

arrayFilters$or 条件一起使用,您可以修改属性time,其中name 字段是给定的属性之一。

arrayFilters 中的 element '变量' 也用于 $set 以更新特定索引。

检查行为是否符合您的预期。

【讨论】:

    【解决方案2】:

    当前的工作代码是stll:

      for (const element of names ) {
        const index = MongoDoc.filter.realms.findIndex(realm => realm.name === element)
        MongoDoc.filter.realms[index].time = Date.now()
      }
      await MongoDoc.save()
    

    但我也发现,原始 Mongoose 文档中的对象字段数组(不是lean() 结果)在某种程度上有点不同。并且它们上的一些 Array.prototype 方法无法正常工作。

    有时最好通过扩展[...array] 运算符将字段的值克隆到一个新数组并直接使用这个新变量,然后完全覆盖该字段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-09
      • 2017-12-16
      • 2014-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多