找一个或用Mongoose创建

时间:2016-10-18 07:42:06

标签: javascript node.js mongodb mongoose mongoose-schema

我有

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

我的问题是,如果没有给出页面ID,它应该在给定条件的情况下获取第一个可用页面,这是由

完成的。
Page.findOne({}).then(page => {
  const pageId = page.id;
  ..
});

但是如果找不到页面,它应该创建一个新页面并使用它,这是用

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

但是如何将所有这些组合成尽可能少的线?

我内心有很多逻辑

page => { ... }

所以我非常希望这样聪明,所以我可以避免这样做

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

我想我也许可以用类似

之类的东西为模式分配一个静态
pageSchema.statics.findOneOrCreate = function (condition, doc, callback) {
  const self = this;
  self.findOne(condition).then(callback).catch((err, result) => {
    self.create(doc).then(callback);
  });
};

8 个答案:

答案 0 :(得分:16)

根据猫鼬docs

根据previous SO answer

Model.findByIdAndUpdate()

“查找匹配的文档,根据更新arg更新它,传递任何选项,并将找到的文档(如果有的话)返回给回调。”

在选项中将upsert设置为true:

upsert:bool - 如果对象不存在则创建它。默认为false。

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

答案 1 :(得分:9)

Yosvel Quintero 答案相关,但对我来说不起作用:

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) })
    })
}

然后使用它:

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

答案 2 :(得分:8)

每个Schema都可以为其模型定义实例和static methods。静态与方法几乎相同,但允许定义直接存在于模型上的函数

静态方法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);
      });
  });
};

现在,如果您拥有Page的实例,则可以致电findOneOrCreate

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

答案 3 :(得分:8)

承诺async/await版本。

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

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

用法

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

或者

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

答案 4 :(得分:3)

使用async/await的单行解决方案:

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

答案 5 :(得分:0)

如果您不想在模型中添加静态方法,可以尝试移动一些内容,至少不要使用所有这些回调嵌套级别:

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;
    });
  }
});

答案 6 :(得分:0)

试试这个..

 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;
    });
  }
});

 }

答案 7 :(得分:0)

使用承诺:

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

然后你可以像这样使用它:

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

或承诺:

Page.findOneOrCreate(id)
.then(page=> /* do something with page*/ )
.catch(err=> /* do something if there's an error*/ )