找一个或用Mongoose创建

Jam*_*een 14 javascript mongoose mongodb node.js mongoose-schema

我有

Page.findById(pageId).then(page => {
  const pageId = page.id;
   ..
});
Run Code Online (Sandbox Code Playgroud)

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

Page.findOne({}).then(page => {
  const pageId = page.id;
  ..
});
Run Code Online (Sandbox Code Playgroud)

但如果没有找到任何页面,它应该创建一个新页面并使用它,这是完成的

Page.create({}).then(page => {
  const pageId = page.id;
  ..
});
Run Code Online (Sandbox Code Playgroud)

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

我内心有很多逻辑

page => { ... }
Run Code Online (Sandbox Code Playgroud)

所以我非常想做到这一点,所以我可以避免这样做

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;
        ..
      });
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

我想我也许可以用类似的东西为模式分配一个静态

pageSchema.statics.findOneOrCreate = function (condition, doc, callback) {
  const self = this;
  self.findOne(condition).then(callback).catch((err, result) => {
    self.create(doc).then(callback);
  });
};
Run Code Online (Sandbox Code Playgroud)

小智 22

根据Mongoose 文档:

按照之前的SO答案

Model.findByIdAndUpdate()

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

在选项中将upsert设置为true:

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

Model.findByIdAndUpdate(id, { $set: { name: 'SOME_VALUE' }}, { upsert: true  }, callback)
Run Code Online (Sandbox Code Playgroud)

  • 如果您没有id,则findOneAndUpdate()也具有相同的upsert选项:https://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate (6认同)
  • 这是一个很好的[Mongoose 更新操作比较表](https://masteringjs.io/tutorials/mongoose/update),突出显示了原子操作。 (2认同)

Nin*_*ham 10

承诺async/await版.

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

  return one || this.create(doc);
});
Run Code Online (Sandbox Code Playgroud)

用法

Page.findOneOrCreate({ id: page.id }, page).then(...).catch(...)
Run Code Online (Sandbox Code Playgroud)

要么

async () => {
  const yourPage = await Page.findOneOrCreate({  id: page.id }, page);
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*oos 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) })
    })
}
Run Code Online (Sandbox Code Playgroud)

然后使用它像:

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

  • 答案不是原子的。 (4认同)
  • 我想,对于 NodsJS 和 Mongoose 用户来说,好消息是“mongoose-find-one-or-create”npm 插件,它的工作原理很迷人,并且像插件一样易于修补到您的数据库模式。希望对小伙伴们有帮助。 (3认同)

Yos*_*ero 8

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

静态方法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);
      });
  });
};
Run Code Online (Sandbox Code Playgroud)

现在当你有一个实例时,Page你可以打电话findOneOrCreate:

Page.findOneOrCreate({id: 'somePageId'}, (err, page) => {
  console.log(page);
});
Run Code Online (Sandbox Code Playgroud)

  • 这不是原子的。 (2认同)