简体   繁体   English

Mongoose - 如果不存在则创建文档,否则,更新 - 在任何一种情况下都返回文档

[英]Mongoose - Create document if not exists, otherwise, update- return document in either case

I'm looking for a way to refactor part of my code to be shorter and simpler, but I don't know Mongoose very well and I'm not sure how to proceed.我正在寻找一种方法来重构我的部分代码,使其更短更简单,但我不太了解 Mongoose,也不知道如何继续。

I am trying to check a collection for the existence of a document and, if it doesn't exist, create it.我正在尝试检查集合中是否存在文档,如果不存在,请创建它。 If it does exist, I need to update it.如果它确实存在,我需要更新它。 In either case I need to access the document's contents afterward.在任何一种情况下,我都需要在之后访问文档的内容。

What I've managed to do so far is query the collection for a specific document and, if it's not found, create a new document.到目前为止,我设法做的是查询特定文档的集合,如果找不到,则创建一个新文档。 If it is found, I update it (currently using dates as dummy data for this).如果找到,我会更新它(目前使用日期作为虚拟数据)。 From there I can access either the found document from my initial find operation or the newly saved document and this works, but there must be a better way to accomplish what I'm after.从那里我可以访问从我的初始find操作中找到的文档或新保存的文档,这很有效,但必须有更好的方法来完成我所追求的。

Here's my working code, sans distracting extras.这是我的工作代码,没有分散注意力的额外内容。

var query = Model.find({
    /* query */
}).lean().limit(1);

// Find the document
query.exec(function(error, result) {
    if (error) { throw error; }
    // If the document doesn't exist
    if (!result.length) {
        // Create a new one
        var model = new Model(); //use the defaults in the schema
        model.save(function(error) {
            if (error) { throw error; }
            // do something with the document here
        });
    }
    // If the document does exist
    else {
        // Update it
        var query = { /* query */ },
            update = {},
            options = {};

        Model.update(query, update, options, function(error) {
            if (error) { throw error; }
            // do the same something with the document here
            // in this case, using result[0] from the topmost query
        });
    }
});

I've looked into findOneAndUpdate and other related methods but I'm not sure if they fit my use case or if I understand how to use them correctly.我研究了findOneAndUpdate和其他相关方法,但我不确定它们是否适合我的用例,或者我是否了解如何正确使用它们。 Can anyone point me in the right direction?谁能指出我正确的方向?

(Probably) Related questions: (可能)相关问题:


Edit编辑

I didn't come across the question pointed out to me in my searching, but after reviewing the answers there I've come up with this.我在搜索中没有遇到向我指出的问题,但是在查看了那里的答案之后,我想出了这个。 It's certainly prettier, in my opinion, and it works, so unless I'm doing something horribly wrong I think my question can probably be closed.在我看来,它当然更漂亮,而且它有效,所以除非我做错了什么可怕的事情,否则我认为我的问题可能会结束。

I would appreciate any additional input on my solution.对于我的解决方案,我将不胜感激。

// Setup stuff
var query = { /* query */ },
    update = { expire: new Date() },
    options = { upsert: true };

// Find the document
Model.findOneAndUpdate(query, update, options, function(error, result) {
    if (!error) {
        // If the document doesn't exist
        if (!result) {
            // Create it
            result = new Model();
        }
        // Save the document
        result.save(function(error) {
            if (!error) {
                // Do something with the document
            } else {
                throw error;
            }
        });
    }
});

You are looking for the new option parameter.您正在寻找new选项参数。 The new option returns the newly created document(if a new document is created). new选项返回新创建的文档(如果创建了新文档)。 Use it like this:像这样使用它:

var query = {},
    update = { expire: new Date() },
    options = { upsert: true, new: true, setDefaultsOnInsert: true };

// Find the document
Model.findOneAndUpdate(query, update, options, function(error, result) {
    if (error) return;

    // do something with the document
});

Since upsert creates a document if not finds a document, you don't need to create another one manually.由于如果没有找到文档, upsert会创建一个文档,因此您无需手动创建另一个文档。

Since you wish to refactor parts of your code to be shorter and simpler,由于您希望将部分代码重构为更短更简单,

  1. Use async / await使用async / await
  2. Use .findOneAndUpdate() as suggested in this answer按照此答案中的建议使用.findOneAndUpdate()

let query = { /* query */ };
let update = {expire: new Date()};
let options = {upsert: true, new: true, setDefaultsOnInsert: true};
let model = await Model.findOneAndUpdate(query, update, options);
///This is simple example explaining findByIDAndUpdate from my code added with try catch block to catch errors
try{
const options = {
            upsert: true,
            new: true,
            setDefaultsOnInsert: true
        };
        const query = {
            $set: {
                description: req.body.description,
                title: req.body.title
            }
        };
        const survey = await Survey.findByIdAndUpdate(
            req.params.id,
            query,
            options
        ).populate("questions");
}catch(e){
console.log(e)
}

Here is an example I am using.这是我正在使用的示例。 I have to return custom responses for UI updates etc. This can be even shorter.我必须为 UI 更新等返回自定义响应。这可以更短。 User is用户是

const UserScheme = mongoose.Schema({
    _id: String,
    name: String,
    city: String,
    address: String,
},{timestamps: true});

const User = mongoose.model('Users', UserScheme);


async function userUpdateAdd(data){
    var resp = '{"status": "error"}';
    if(data){
    var resp = await User.updateOne({ _id: data._id }, data).then(function(err, res){
        console.log("database.userUpdateAdd -> Update data saved in database!");
        if(err){
            var errMessage = err.matchedCount == 0 ? "User Record does not exist, will create new..." : "Record not updated";
            // If no match, create new
            if(err.matchedCount == 0){
                const create_user = new User(data);
                resp = create_user.save().then(function(){
                    console.log("database.userUpdateAdd -> Data saved to database!");
                    return '{"status":"success", "message": "New User added successfully"}';
                });
                return resp;
            }

            // Exists, return success update message
            if(err.matchedCount == 1){
                return '{"status": "success", "message" : "Update saved successfully"}';
            } else {
                return '{"status": "error", "code": "' + err.modifiedCount + '", "message": "' + errMessage + '"}';
            }
        }
        })
        .catch((error) => {
            //When there are errors We handle them here
            console.log("database.userUpdateAdd -> Error, data not saved! Server error");
            return '{"status": "error", "code": "400", "message": "Server error!"}';
        });
    }
    return resp;
}

Here's an example:下面是一个例子:

 const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/rsvp', {useNewUrlParser: true, useUnifiedTopology: true}); const db = mongoose.connection; db.on('error', () => { console.log('mongoose connection error'); }); db.once('open', () => { console.log('mongoose connected successfully'); }); const rsvpSchema = mongoose.Schema({ firstName: String, lastName: String, email: String, guests: Number }); const Rsvp = mongoose.model('Rsvp', rsvpSchema); // This is the part you will need... In this example, if first and last name match, update email and guest number. Otherwise, create a new document. The key is to learn to put "upsert" as the "options" for the argument. const findRsvpAndUpdate = (result, callback) => { Rsvp.findOneAndUpdate({firstName: result.firstName, lastName: result.lastName}, result, { upsert: true }, (err, results) => { if (err) { callback(err); } else { callback(null, results); } }) }; // From your server index.js file, call this... app.post('/rsvps', (req, res) => { findRsvpAndUpdate(req.body, (error, result) => { if (error) { res.status(500).send(error); } else { res.status(200).send(result); } }) });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM