也许是时间的问题,也许是我淹没在稀疏的文档中,无法理解Mongoose中的更新概念:)

事情是这样的:

我有一个联系模式和模型(缩短属性):

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var mongooseTypes = require("mongoose-types"),
    useTimestamps = mongooseTypes.useTimestamps;


var ContactSchema = new Schema({
    phone: {
        type: String,
        index: {
            unique: true,
            dropDups: true
        }
    },
    status: {
        type: String,
        lowercase: true,
        trim: true,
        default: 'on'
    }
});
ContactSchema.plugin(useTimestamps);
var Contact = mongoose.model('Contact', ContactSchema);

我从客户端收到一个请求,包含我需要的字段,然后使用我的模型:

mongoose.connect(connectionString);
var contact = new Contact({
    phone: request.phone,
    status: request.status
});

现在问题来了:

If I call contact.save(function(err){...}) I'll receive an error if the contact with the same phone number already exists (as expected - unique) I can't call update() on contact, since that method does not exist on a document If I call update on the model: Contact.update({phone:request.phone}, contact, {upsert: true}, function(err{...}) I get into an infinite loop of some sorts, since the Mongoose update implementation clearly doesn't want an object as the second parameter. If I do the same, but in the second parameter I pass an associative array of the request properties {status: request.status, phone: request.phone ...} it works - but then I have no reference to the specific contact and cannot find out its createdAt and updatedAt properties.

因此,我的底线是:给定一个文档联系人,如果它存在,我如何更新它,如果它不存在,我如何添加它?

谢谢你的时间。


当前回答

app.put('url', function(req, res) {

        // use our bear model to find the bear we want
        Bear.findById(req.params.bear_id, function(err, bear) {

            if (err)
                res.send(err);

            bear.name = req.body.name;  // update the bears info

            // save the bear
            bear.save(function(err) {
                if (err)
                    res.send(err);

                res.json({ message: 'Bear updated!' });
            });

        });
    });

这里有一个更好的方法来解决猫鼬的更新方法,你可以检查苏格兰。IO了解更多详情。这绝对对我有用!!

其他回答

我只是在一段时间后回到这个问题上,并决定基于Aaron Mast的答案发布一个插件。

https://www.npmjs.com/package/mongoose-recursive-upsert

将其作为猫鼬插件使用。它设置一个静态方法,递归地合并传入的对象。

Model.upsert({unique: 'value'}, updateObject});

我是猫鼬的维护者。插入文档的更现代的方法是使用Model.updateOne()函数。

await Contact.updateOne({
    phone: request.phone
}, { status: request.status }, { upsert: true });

如果你需要插入的文档,你可以使用Model.findOneAndUpdate()

const doc = await Contact.findOneAndUpdate({
    phone: request.phone
}, { status: request.status }, { upsert: true, useFindAndModify: false });

关键是,您需要将过滤器参数中的唯一属性放到updateOne()或findOneAndUpdate()中,并将其他属性放到更新参数中。

这是一个用Mongoose上传文档的教程。

User.findByIdAndUpdate(req.param('userId'), req.body, (err, user) => {
    if(err) return res.json(err);

    res.json({ success: true });
});

对于任何到达这里仍然在寻找一个好的解决方案“upserting”与钩子支持,这是我已经测试和工作。它仍然需要2个DB调用,但比我在一次调用中尝试过的任何东西都稳定得多。

// Create or update a Person by unique email.
// @param person - a new or existing Person
function savePerson(person, done) {
  var fieldsToUpdate = ['name', 'phone', 'address'];

  Person.findOne({
    email: person.email
  }, function(err, toUpdate) {
    if (err) {
      done(err);
    }

    if (toUpdate) {
      // Mongoose object have extra properties, we can either omit those props
      // or specify which ones we want to update.  I chose to update the ones I know exist
      // to avoid breaking things if Mongoose objects change in the future.
      _.merge(toUpdate, _.pick(person, fieldsToUpdate));
    } else {      
      toUpdate = person;
    }

    toUpdate.save(function(err, updated, numberAffected) {
      if (err) {
        done(err);
      }

      done(null, updated, numberAffected);
    });
  });
}

在阅读了上面的文章之后,我决定使用下面的代码:

    itemModel.findOne({'pid':obj.pid},function(e,r){
        if(r!=null)
        {
             itemModel.update({'pid':obj.pid},obj,{upsert:true},cb);
        }
        else
        {
            var item=new itemModel(obj);
            item.save(cb);
        }
    });

如果r为空,则创建新项。否则,在update中使用upsert,因为update不会创建新项。