也许是时间的问题,也许是我淹没在稀疏的文档中,无法理解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.

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

谢谢你的时间。


当前回答

下面是创建/更新同时调用中间件和验证器的最简单方法。

Contact.findOne({ phone: request.phone }, (err, doc) => {
    const contact = (doc) ? doc.set(request) : new Contact(request);

    contact.save((saveErr, savedContact) => {
        if (saveErr) throw saveErr;
        console.log(savedContact);
    });
})

其他回答

2.6引入了一个bug,影响到2.7

upsert过去在2.4上正常工作

https://groups.google.com/forum/ !主题/ mongodb-user / UcKvx4p4hnY https://jira.mongodb.org/browse/SERVER-13843

看一下,它包含了一些重要的信息

更新:

这并不意味着upsert不起作用。下面是一个如何使用它的好例子:

User.findByIdAndUpdate(userId, {online: true, $setOnInsert: {username: username, friends: []}}, {upsert: true})
    .populate('friends')
    .exec(function (err, user) {
        if (err) throw err;
        console.log(user);

        // Emit load event

        socket.emit('load', user);
    });

我需要更新/upsert一个文档到一个集合,我所做的是创建一个新的对象文字如下:

notificationObject = {
    user_id: user.user_id,
    feed: {
        feed_id: feed.feed_id,
        channel_id: feed.channel_id,
        feed_title: ''
    }
};

由我从数据库中其他地方获得的数据组成,然后在模型上调用update

Notification.update(notificationObject, notificationObject, {upsert: true}, function(err, num, n){
    if(err){
        throw err;
    }
    console.log(num, n);
});

这是我第一次运行脚本后得到的输出:

1 { updatedExisting: false,
    upserted: 5289267a861b659b6a00c638,
    n: 1,
    connectionId: 11,
    err: null,
    ok: 1 }

这是我第二次运行脚本时的输出:

1 { updatedExisting: true, n: 1, connectionId: 18, err: null, ok: 1 }

我使用的是猫鼬3.6.16版本

我是猫鼬的维护者。插入文档的更现代的方法是使用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上传文档的教程。

这个coffeescript为我与节点工作-技巧是_id获取剥离了它的ObjectID包装时,发送和返回从客户端,所以这需要替换为更新(当没有_id提供,保存将恢复到插入和添加一个)。

app.post '/new', (req, res) ->
    # post data becomes .query
    data = req.query
    coll = db.collection 'restos'
    data._id = ObjectID(data._id) if data._id

    coll.save data, {safe:true}, (err, result) ->
        console.log("error: "+err) if err
        return res.send 500, err if err

        console.log(result)
        return res.send 200, JSON.stringify result

下面是创建/更新同时调用中间件和验证器的最简单方法。

Contact.findOne({ phone: request.phone }, (err, doc) => {
    const contact = (doc) ? doc.set(request) : new Contact(request);

    contact.save((saveErr, savedContact) => {
        if (saveErr) throw saveErr;
        console.log(savedContact);
    });
})