Как обновить несколько полей объекта массива одним запросом?

1
{
   _id:xxxxstoreid
    store:{
        products:[
            {
                _id:xxxproductid,
                name:xxx,
                img:url,
            }
        ]
    }
}

поскольку я не могу предсказать запрос на обновление, параметры могут иметь только имя или могут иметь оба.

вот мой запрос, он успешно обновляется, но он удаляет другие поля, если они не присутствуют в параметрах. например:

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);
  • 0
    Есть ли в представленном ответе что-то, что, по вашему мнению, не отвечает вашему вопросу? Если это так, то, пожалуйста, прокомментируйте ответ, чтобы уточнить, что именно нужно решать, а что нет. Если он действительно ответит на заданный вами вопрос, пожалуйста, отметьте « Принять ваши ответы» на заданные вами вопросы.
Теги:
mongoose
mongodb-query

3 ответа

4
Лучший ответ

Вам необходимо предоставить несколько ключей в $set с оператором positional $ для обновления обоих совпадающих ключей.

Я предпочитаю современный способ обработки объектов 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 []: который позволяет имена переменных в объектных литералах.

Полученный "объединенный" объект передается обратно для назначения "корневому" объекту, где для ключа обновления используется $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)
}
  • 0
    Могу ли я сделать это с помощью поиска и обновления?
  • 0
    Я не уверен, что ты имеешь в виду. Кроме того, я забыл упомянуть, что поле products представляет собой массив, поэтому вы не можете получить к нему доступ. Ваш вопрос нуждается в более подробной информации, например, что именно вы называете params.
Показать ещё 7 комментариев
1

В приведенном ниже запросе будет использоваться оператор $ positional для нахождения элемента массива по индексу, найденному в результате сопоставления массива с помощью _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);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню