2013-06-21 4 views
11

Я хотел бы иметь один метод, который либо создает, либо обновляет документ для политики. Поиск и использование различных методов, таких как this one, я придумал нулевой _id для моего документа. Использование findByIdAndUpdate имеет аналогичный аффект.Mongoose findOneAndUpdate Upsert _id null?

Я вижу документ, вставленный в коллекции, но поле _id равно нулю:

exports.savePolicy = function (plcy, callback) { 
    console.log('priority is : ' + plcy.priority) 
    try { 
     var policy = new Policy(plcy); 
     var query = {_id: plcy._id}; //this may be null 
     var update = { 
      name: plcy.name || defaults.policyDefaults.name, 
      longDescription: plcy.longDescription || defaults.policyDefaults.longDescription, 
      shortDescription: plcy.shortDescription || defaults.policyDefaults.shortDescription, 
      priority: plcy.priority, colorHex: plcy.colorHex || defaults.policyDefaults.colorHex, 
      settings: plcy.settings || [], 
      parentPolicyId: plcy.parentPolicyId || null 
     } 

     Policy.findOneAndUpdate(query, update, {upsert: true}, function (err, data) { 
      callback(err, data); 
     }); 

    } catch (e) { 
     log.error('Exception while trying to save policy: ' + e.message); 
     callback(e, null); 
    } 

Есть ли что-то, что можно сделать, чтобы получить _id не быть пустым, если его не обновление?

+0

вы когда-нибудь понять это? У меня была такая же проблема. Я закончил проверку на _id вручную, а затем вызвал либо findOneAndUpdate для обновления, либо create() для новой записи. – Trent

ответ

-3

Попробуйте установить для параметра upsert значение true в вашем запросе для обновления. Из миндальных документов: http://docs.mongodb.org/manual/reference/method/db.collection.update/#update-parameter

Дополнительно. Если установлено значение true, создается новый документ, если документ не соответствует критериям запроса. Значение по умолчанию - false, которое не вставляет новый документ, если совпадение не найдено.

5

У меня была эта же проблема и я не мог понять, как заставить ее работать. Я закончил тем, что писал мой собственный метод upsert как так ....

var upsert = function(model, data, f){ 
    if (!data._id) { 
    model.create(data, f); 
    } else { 
    var id = data._id; 
    delete data._id; 
    model.findOneAndUpdate({_id: id}, data, f); 
    } 
} 

Это позволяет мне назвать это для любого из моих моделей с одной строки кода ...

upsert(Team, team, f); 

Там может быть лучший способ сделать это, но это работает для меня. Я могу делать обновления и вставки, и я не получаю нуль _id при вставке.

+0

Ну, вы можете решить эту проблему, используя что-то вроде этого: Model.findOneAndUpdate ({_id: id || Mongoose.Types.ObjectId()}, {$ set: attrs}, {upsert: true, new: true}) –

11

null является действительным _id значения в MongoDB, так что если вы не хотите использовать в новых документах, вы должны убедиться, что значение null заменяются новый ObjectID в query:

var query = {_id: plcy._id}; 
if (!query._id) { 
    query._id = new mongoose.mongo.ObjectID(); 
} 

// the rest stays the same... 
+0

Мы используем ObjectIds для создания временной метки создания. Разве не лучше, чтобы ObjectIds создавались на стороне сервера вместо клиентов, создающих их? – dhaundy

1

Я не используя Mongoose, но я столкнулся с аналогичной проблемой с MongoDB. Для действия Upsert при вставке нового объекта MongoDB установил null в _id.

Я звала:

findOneAndUpdate({my_id:'my_unique_id'}, obj, {upsert: true}) 

где obj._id был undefined.

Проблема в том, что _id был указан в списке ключей Object.keys(obj). Я обнаружил, что назначал obj._id = some_variable, где some_variable был undefined, и это вызывало появление _id в списке ключей.

я применил обходной путь по телефону прямо перед upsert:

if (_.isUndefined(obj._id)) { 
    delete obj._id; 
} 
0

Благодаря JohnnyHK за полезный ответ выше.Я придумал однострочника, так как он используется так часто:

query = args._id ? { _id: args._id } : { _id: new ObjectId() }; 

Он опирается на следующие требуют:

const ObjectId = require('mongodb').ObjectID;