可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have
Page.findById(pageId).then(page => {
const pageId = page.id;
..
});
My problem is that if no page id is given, it should just take the first available page given some conditions, which is done by
Page.findOne({}).then(page => {
const pageId = page.id;
..
});
but if no page is found, it should create a new page and use this, which is done with
Page.create({}).then(page => {
const pageId = page.id;
..
});
But how do I combine all this to as few lines as possible?
I have a lot of logic going on inside
page => { ... }
so I would very much like to do this smart, so I can avoid doing it like this
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;
..
});
}
});
}
I am thinking I maybe could assign a static to the schema with something like
pageSchema.statics.findOneOrCreate = function (condition, doc, callback) {
const self = this;
self.findOne(condition).then(callback).catch((err, result) => {
self.create(doc).then(callback);
});
};
回答1:
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)
})
回答2:
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)
回答3:
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);
});
回答4:
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);
}
回答5:
One lines solution with async/await
:
const page = Page.findOne({}).then(p => p || p.create({})
回答6:
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;
});
}
});
回答7:
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;
});
}
});
}
回答8:
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*/ )