【问题标题】:How to update multiple fields of an array object with one request?如何通过一个请求更新数组对象的多个字段?
【发布时间】:2020-02-28 09:42:59
【问题描述】:
{
   _id:xxxxstoreid
    store:{
        products:[
            {
                _id:xxxproductid,
                name:xxx,
                img:url,
            }
        ]
    }
}

由于我无法预测更新请求,params 可能只有名称,也可能两者都有。

这是我的查询,它更新成功,但如果其他字段不存在于参数中,它会删除它们。 例如:

var params={_id:xxid,name:'xxx',img:'xxx'}

var params={_id:xxid,name:'xxx'}

在这种情况下,如果 params 刚刚命名,它会删除 img 字段并更新。

User.update({'store.products._id':params._id},{$set:{"store.products":params}},callback);

【问题讨论】:

  • 您认为提供的答案中是否有某些内容无法解决您的问题?如果是这样,请对答案发表评论,以澄清究竟需要解决哪些尚未解决的问题。如果它确实回答了您提出的问题,请注意Accept your Answers您提出的问题

标签: javascript node.js mongodb mongoose mongodb-query


【解决方案1】:

您需要使用positional $ operator$set 提供多个密钥以更新两个匹配的密钥。

我更喜欢现代 ES6 的对象操作方式:

let params = { "_id" : "xxxproductid", "name" : "xxx", "img" : "yyy" };

let update = [
  { 'store.products._id': params._id },
  { "$set": Object.keys(params).filter(k => k != '_id')
    .reduce((acc,curr) =>
      Object.assign(acc,{ [`store.products.$.${curr}`]: params[curr] }),
    { })
  }
];

User.update(...update,callback);

这会产生对 MongoDB 的调用,因为(mongoose.set('debug', true))打开所以我们看到了请求:

Mongoose: users.update({ 'store.products._id': 'xxxproductid' }, { '$set': { 'store.products.$.name': 'xxx', 'store.products.$ .img': 'yyy' } }, {})

基本上,您将输入 params 并提供 _id 作为“查询”的第一个参数:

  { 'store.products._id': params._id },

其余部分通过Object.keys 从对象中获取“键”,这会生成一个“数组”,我们可以使用Array.filter() 对其进行“过滤”,然后传递给Array.reduce 以将这些键转换为Object

.reduce() 内部,我们调用Object.assign(),它将对象与给定的键“合并”,以这种形式生成:

  Object.assign(acc,{ [`store.products.$.${curr}`]: params[curr] }),

使用模板语法将“当前”(当前)“键”分配给新键名,再次使用ES6 key assignment syntax []:,它允许在对象字面量中使用变量名。

生成的“合并”对象被传回以分配给“根”对象,其中$set 用于更新的键,因此“生成的”键现在是它的子对象。

我使用数组作为参数纯粹是出于调试目的,但这也允许在实际 .update() 上使用“spread”... 运算符来分配参数的更简洁的语法:

User.update(...update,callback);

简洁明了,以及一些您应该学习的用于对象和数组操作的 JavaScript 技术。主要是因为 MongoDB 查询 DSL 基本上是“对象”和“数组”。所以学会操纵它们。

【讨论】:

    【解决方案2】:
    function updateProducts(params) {
        var query = {'store.products': {$elemMatch: {_id: params._id}}}
        var updateObject = null;
        if (params.name && params.img) {
            updateObject = {$set: {'store.products.$': params}}
        } else if(params.name && !params.img) {
            updateObject = {$set: {'store.products.$.name': params.name}}    
        } else if (params.img && !params.name) {
            updateObject = {$set: {'store.products.$.img': params.img}}  
        }
    
        User.update(query, updateObject, callback)
    }
    

    【讨论】:

    • 我不确定你的意思。另外,我忘了提,products 字段是一个数组,所以你不能访问它的属性。您的问题需要更多细节,例如您所说的 params 到底是什么。
    • 在猫鼬中有一种方法可以做 findOne 并保存 ryt?
    • 那么在这种情况下我该怎么做呢?正如你所说的 products 是一个数组,我怎么知道要更新哪个索引?我应该循环产品并将其与参数匹配吗?
    • 我对猫鼬不熟悉,所以无法回答。
    • 如果您不确定需要更新数组中的哪个元素,请使用位置运算符更新数组中的元素。见[这里] (docs.mongodb.com/manual/reference/operator/update/positional)
    【解决方案3】:

    下面的查询将使用$ 位置运算符在查询文档中通过与_id 匹配的数组找到索引处的数组元素,然后使用params 值更新该元素的字段。

    var params = {_id:1, name:'xxx',img:'yyy'};
    var id = params['_id']; // Get id to locate matching array index
    delete params['_id']; // Remove id from the object
    Object.keys(params).forEach(function (key){params['store.products.$.'+key] = params[key]; delete params[key];}) // Transforms remaining object keys to include the positional $ placeholder to { "store.products.$.name" : "xxx", "store.products.$.img" : "yyy" }
    
    User.update('store.products._id':id},{$set:params},callback);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-26
      • 1970-01-01
      • 2020-05-03
      • 2023-01-24
      • 1970-01-01
      • 1970-01-01
      • 2021-08-23
      相关资源
      最近更新 更多