使用 Mongoose 查找或创建
Find one or create with Mongoose
我有
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);
});
};
每个模式都可以为其模型定义实例和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);
});
如果您不想向模型添加静态方法,您可以尝试移动一些东西,至少不要让所有这些回调嵌套级别:
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;
});
}
});
试试这个..
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;
});
}
});
}
与 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)
})
承诺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);
}
根据猫鼬 docs:
根据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."
在选项中将 upsert 设置为 true:
upsert: bool - 如果对象不存在则创建它。默认为假。
Model.findByIdAndUpdate(id, { $set: { name: 'SOME_VALUE' }}, { upsert: true }, callback)
async/await
的一行解决方案:
const page = Page.findOne({}).then(p => p || p.create({})
此处发布的解决方案忽略了当字段或字段组合上有唯一索引时,这种模式最常见。此解决方案正确考虑唯一索引违规错误:
mongoose.plugin((schema) => {
schema.statics.findOrCreate = async function findOrCreate(attrs) {
try {
return await this.create(attrs);
} catch (error) {
const isDuplicate = error.code === 11000 && error.keyPattern;
if (isDuplicate) {
const doc = await this.findOne(error.keyValue);
doc.set(attrs);
return await doc.save();
}
throw error;
}
};
});
我有
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);
});
};
每个模式都可以为其模型定义实例和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);
});
如果您不想向模型添加静态方法,您可以尝试移动一些东西,至少不要让所有这些回调嵌套级别:
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;
});
}
});
试试这个..
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;
});
}
});
}
与 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)
})
承诺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);
}
根据猫鼬 docs:
根据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."
在选项中将 upsert 设置为 true:
upsert: bool - 如果对象不存在则创建它。默认为假。
Model.findByIdAndUpdate(id, { $set: { name: 'SOME_VALUE' }}, { upsert: true }, callback)
async/await
的一行解决方案:
const page = Page.findOne({}).then(p => p || p.create({})
此处发布的解决方案忽略了当字段或字段组合上有唯一索引时,这种模式最常见。此解决方案正确考虑唯一索引违规错误:
mongoose.plugin((schema) => {
schema.statics.findOrCreate = async function findOrCreate(attrs) {
try {
return await this.create(attrs);
} catch (error) {
const isDuplicate = error.code === 11000 && error.keyPattern;
if (isDuplicate) {
const doc = await this.findOne(error.keyValue);
doc.set(attrs);
return await doc.save();
}
throw error;
}
};
});