Find one or create with Mongoose

江枫思渺然 提交于 2019-11-28 10:58:06

Related to Yosvel Quintero's answer which didn't work for me:

pageSchema.statics.findOneOrCreate = function findOneOrCreate(condition, callback) {
    const self = this
    self.findOne(condition, (err, result) => {
        return result ? callback(err, result) : self.create(condition, (err, result) => { return callback(err, result) })
    })
}

And then use it like:

Page.findOneOrCreate({ key: 'value' }, (err, page) => {
    // ... code
    console.log(page)
})

As per the Mongoose docs:

As per previous SO answer

Model.findByIdAndUpdate()

"Finds a matching document, updates it according to the update arg, passing any options, and returns the found document (if any) to the callback."

In the options set upsert to true:

upsert: bool - creates the object if it doesn't exist. defaults to false.

Model.findByIdAndUpdate(id, { $set: { name: 'SOME_VALUE' }}, { upsert: true  }, callback)

Each Schema can define instance and static methods for its model. Statics are pretty much the same as methods but allow for defining functions that exist directly on your Model

Static method findOneOrCreate:

pageSchema.statics.findOneOrCreate = function findOneOrCreate(condition, doc, callback) {
  const self = this;
  self.findOne(condition, (err, result) => {
    return result 
      ? callback(err, result)
      : self.create(doc, (err, result) => {
        return callback(err, result);
      });
  });
};

Now when you have an instance of Page you can call findOneOrCreate:

Page.findOneOrCreate({id: 'somePageId'}, (err, page) => {
  console.log(page);
});

Promise async/await version.

Page.static('findOneOrCreate', async function findOneOrCreate(condition, doc) {
  const one = await this.findOne(condition);

  return one || this.create(doc);
});

Usage

Page.findOneOrCreate({ id: page.id }, page).then(...).catch(...)

Or

async () => {
  const yourPage = await Page.findOneOrCreate({  id: page.id }, page);
}

One lines solution with async/await:

const page = Page.findOne({}).then(p => p || p.create({})

If you don't want to add a static method to the model, you can try to move some things around and at least not to have all these callback nested levels:

function getPageById (callback) {
  Page.findById(pageId).then(page => {
    return callback(null, page);
  });
}

function getFirstPage(callback) {
  Page.findOne({}).then(page => {
    if (page) {
      return callback(null, page);
    }

    return callback();
  });
}

let retrievePage = getFirstPage;
if (pageId) {
  retrievePage = getPageById;
}

retrievePage(function (err, page) {
  if (err) {
    // @todo: handle the error
  }

  if (page && page.id) {
    pageId = page.id;
  } else {
    Page.create({}).then(page => {
      pageId = page.id;
    });
  }
});

try this..

 var myfunc = function (pageId) {
  // check for pageId passed or not
 var newId = (typeof pageId == 'undefined') ? {} : {_id:pageId};

 Page.findOne(pageId).then(page => {
 if (page)
 const pageId = page.id;
 else {  // if record not found, create new

    Page.create({}).then(page => {
        const pageId = page.id;
    });
  }
});

 }

Using promises :

pageSchema.statics.findOneOrCreate = function(id, cb){
  return (id?this.findById(id, cb):this.findOne({}, cb))
  .then(page=>page? page : this.create({}, cb))
}

then you can use it like this:

Page.findOneOrCreate(pageId, (err, page)=>{
  if(err){
    //if theres an error, do something
  }
  //  or do something with the page
})

or with promises:

Page.findOneOrCreate(id)
.then(page=> /* do something with page*/ )
.catch(err=> /* do something if there's an error*/ )
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!