2015-08-16 2 views
0

Итак, я работаю с NodeJS и MongoDB, и я делаю конечную точку, которая позволяет клиентам обновлять свои профили пользователей несколькими необязательными полями данных. Так, один из запросов обновления может выглядеть следующим образом:findByIdAndUpdate С несколькими поддокументами

{ 
    name: { givenName: 'first' }, 
    about: 'whatever', 
    auth: { password: 'hashedPW' } 
} 

мангуст API Docs указать следующую информацию о findByIdAndUpdate: Все главные ключи обновления уровня, которые не являются атомными имена операций рассматриваются как набор операций.

Таким образом, клавиша верхнего уровня, about, отлично работает для обновления. Однако вложенные ключи name и auth будут перезаписаны значениями обновления, а не только установлены значения.

Теперь я мог бы пройти и вручную изменить каждое из полей, чтобы быть $set ключом, но есть много разных полей, поэтому делать это было бы довольно неприятно. Есть ли простой способ применить правило $ set к поддокументам? то есть преобразование оператора в этом, с опцией Mongoose или что-то:

{ 
    $set : { name: { givenName: 'first' } }, 
    $set : { about: 'whatever' }, 
    $set : { auth: { password: 'hashedPW' } } 
} 
+0

Вы обычно должны быть в состоянии просто добавить полный объект в качестве второго параметра ... –

+0

На основании документации-х формулировка, я не думаю, что это так; Я думаю, что это относится только к клавишам верхнего уровня. http://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate –

+0

У меня нет компьютера atm, поэтому я не могу его протестировать. В большинстве случаев я работаю с * update * вместо * findByIdAndUpdate * и работает для вложенных ключей. –

ответ

1

Вы в основном нужно или обработка входной объект в "dot notation" форму для того, чтобы избежать overwring другие возможные суб-ключи в обновлении. Это довольно просто:

var obj = { 
    name: { givenName: 'first' }, 
    about: 'whatever', 
    auth: { password: 'hashedPW' } 
}; 

var target = {}; 

function dotNotate(obj,prefix) { 
    prefix = (typeof(prefix) === 'undefined') ? "" : prefix; 
    Object.keys(obj).forEach(function(key) { 
    if (typeof(obj[key]) === "object") { 
     dotNotate(obj[key],key + ".") 
    } else { 
     target[prefix + key] = obj[key]; 
    } 
    }); 
} 

dotNotate(obj); 

Теперь target объект выглядит следующим образом:

{ 
    "name.givenName" : "first", 
    "about" : "whatever", 
    "auth.password" : "hashedPW" 
} 

Так обновление блока вашего утверждения просто записывается в виде:

{ "$set": target } 

Для справки функция dotNotate() может быть немного более усовершенствованной и автономной. Кроме того, в том числе более короткие назначения по умолчанию в качестве действительного ввода, как правило, считаются «правдивыми». Кроме того, «префикс» должен быть предварительно затрачиваемая при каждом вызове, чтобы сделать эту работу на произвольную глубину:

function dotNotate(obj,target,prefix) { 
    target = target || {}, 
    prefix = prefix || ""; 

    Object.keys(obj).forEach(function(key) { 
    if (typeof(obj[key]) === "object") { 
     dotNotate(obj[key],target,prefix + key + "."); 
    } else { 
     return target[prefix + key] = obj[key]; 
    } 
    }); 

    return target; 
} 

Затем вы можете использовать либо встроенный:

var update = { "$set": dotNotate(obj) }; 

Или передать в определенный объект, например, это, если хотите:

var update = { "$set": {} }; 
dotNotate(obj,update["$set"]); 

С такими же результатами.

Также отлично подходит для массивов и вложенной глубина:

{ 
    "things" : [ 
     { 
      "a" : 1, 
      "b" : 2 
     }, 
     { 
      "a" : 3, 
      "b" : 4 
     } 
    ], 
    "bool" : false 
} 

С выходом:

{ 
    "things.0.a" : 1, 
    "things.0.b" : 2, 
    "things.1.a" : 3, 
    "things.1.b" : 4, 
    "bool" : false 
} 
Смежные вопросы