首页 > 解决方案 > MongoDB 获取 ArrayFilters 引用以更新值

问题描述

我最近开始使用 MongoDB,我正在尝试更新文档中的一些属性,但无法获取对象引用来更新值。

请考虑以下数据:

const data = {
 weekplanId: 'someid',
 days: [
  {label: 'Monday', cost: 20, comment: "some comment" },
  {label: 'Tuesday', cost: 40, comment: "..." }
 ]
}

const update = await weekplan.updateOne(
    {
      _id: new ObjectId(data.weekplanId),
    },
    {
      $set: {
        "weekdays.$[i].cost": data.days.$[i].cost,
        "weekdays.$[i].comment": data.days.$[i].comment,
        "weekdays.$[i].date": new Date(),
        "weekdays.$[i].someproperty": "something",
      }
    },
    {
      arrayFilters: [
        {
          "i.label": {
            $in: data.days.map(p => p.label),
          },
        }]
    }
  );

如何引用数组对象来设置属性值?我知道data.days.$[i].cost并且data.days.$[i].comment错了,它们只是我努力实现的一个例子。

设置datesomeproperty按预期工作,因为这些值不依赖于源数据。

我想尝试在不使用 JS 的情况下做到这一点。

arrayFilters 甚至适合这个吗?我会很感激一些关于在哪里看的指导。

提前致谢!

###编辑:

预期输出:

 "_id": {"someid"},
 "weekdays": [
    {
        "day": "Monday",
        "cost": 20,
        "comment": "some comment",
        "date": 2021-08-01T19:51:45.057Z
        "someproperty": "something"
    },
    {
        "day": "Tuesday",
        "cost": 40,
        "comment": "...",
        "date": 2021-08-01T19:51:45.057Z
        "someproperty": "something"
    },
    ...
    ...
    ...
]

工作日的其余时间(周三、周四、周五)将在此更新中保持不变。

标签: javascriptmongodb

解决方案


在该示例代码data.days.$[i].cost中,在提交查询之前在客户端评估代码,因此$set当服务器接收到它时,将分配给对象的相应字段的任何值(或缺少值)。

data对象不会随查询一起发送到服务器,因此即使它能够对输入值进行数组查找,输入值也不存在。

实现这一点的方法是在客户端迭代数组,并以编程方式构建更新查询。也许是这样的:

let labelChar = 105;
let setOps = {};
let filters = {};
data.days.forEach( function(day) {
  let char = String.fromCharCode(labelChar++);
  setOps['weekdays.$[' + char + '].cost'] = day.cost;
  setOps['weekdays.$[' + char + '].comment'] = day.comment;
  setOps['weekdays.$[' + char + '].date'] = new Date();
  setOps['weekdays.$[' + char + '].someproperty'] = "something";
  let filterObj = {};
  filterObj[char + '.label'] = day.label;
  filters.push(filterObj);
});
const update = await weekplan.updateOne(
    {
      _id: new ObjectId(data.weekplanId),
    },
    {
      $set: setOps
    },
    {
      arrayFilters: filters
    }
  );

对于提供的示例输入,这将提供更新:

.updateOne(
    {
      _id: new ObjectId(data.weekplanId),
    },
    {
      $set: {
             'weekdays.$[i].cost': 20,
             'weekdays.$[i].comment': 'some comment',
             'weekdays.$[i].date': ISODate(),
             'weekdays.$[i].someproperty': 'something',
             'weekdays.$[j].cost': 40,
             'weekdays.$[j].comment': '...',
             'weekdays.$[j].date': ISODate(),
             'weekdays.$[j].someproperty': 'something'
            }
    },
    {
      arrayFilters: [
                     {'i.label': 'Monday'}, 
                     {'j.label': 'Tuesday'}
                    ]
    }
  );

推荐阅读