Node.js (mongoose/Promissions)如何检查文档是否是使用findOneAndUpdate和upsert创建的
考虑一下这段代码,我需要创建或更新一个特定的文档Node.js (mongoose/Promissions)如何检查文档是否是使用findOneAndUpdate和upsert创建的,node.js,mongodb,mongoose,promise,mongodb-query,Node.js,Mongodb,Mongoose,Promise,Mongodb Query,考虑一下这段代码,我需要创建或更新一个特定的文档 Inbox.model.findOneAndUpdate({ number: req.phone.number }, { number: req.phone.number, country: req.phone.country, token: hat(), appInstalled: true }, { new: true, upsert: true }).then(function(inbox){ /*
Inbox.model.findOneAndUpdate({ number: req.phone.number }, {
number: req.phone.number,
country: req.phone.country,
token: hat(),
appInstalled: true
}, { new: true, upsert: true }).then(function(inbox){
/*
do something here with inbox, but only if the inbox was created (not updated)
*/
});
猫鼬是否有一个设施能够区分文件是否被创建或更新?我需要new:true
,因为我需要调用收件箱中的函数
对于mongoose的.findAndModify()
核心驱动程序变体,实际的回调签名有“三个”参数:
function(err,result,raw)
第一个是任何错误响应,然后是修改的或原始文档(取决于选项),第三个是已发布语句的写入结果
第三个参数应该返回如下数据:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e12c65f6044f57c8e09a46 },
value: { _id: 55e12c65f6044f57c8e09a46,
number: 55555555,
country: 'US',
token: "XXX",
appInstalled: true,
__v: 0 },
ok: 1 }
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e13bcbf6044f57c8e09a4b },
value: { _id: 55e13bcbf6044f57c8e09a4b, name: 'Bill' },
ok: 1 }
其中的一致字段为lastErrorObject.updatedExisting
为true/false
,具体取决于是否发生upsert的结果。请注意,当此属性为false
时,也有一个“upserted”值,其中包含新文档的\u id
响应,但当该属性为true
时则没有
这样,你就可以修改你的操作来考虑第三个条件,但是这只能用回调而不是承诺:
Inbox.model.findOneAndUpdate(
{ "number": req.phone.number },
{
"$set": {
"country": req.phone.country,
"token": hat(),
"appInstalled": true
}
},
{ "new": true, "upsert": true },
function(err,doc,raw) {
if ( !raw.lastErrorObject.updatedExitsing ) {
// do things with the new document created
}
}
);
我还强烈建议您在这里使用而不是原始对象,因为原始对象总是会覆盖整个文档,而像这样的操作符只会影响列出的字段
还要注意的是,任何与语句匹配的“查询参数”都会自动分配到新文档中,只要它们的值与未找到的值完全匹配
由于某种原因,使用承诺似乎不会返回附加信息,因此,除了设置{new:false}
之外,不知道使用承诺如何实现这一点,基本上,当没有返回文档时,它就是一个新的文档
您已经拥有了所有预期插入的文档数据,因此并不需要返回这些数据。事实上,本机驱动程序方法是如何在核心处理这个问题的,并且只有在发生upsert时才使用“upserted”\u id
值进行响应
这实际上涉及到本网站上讨论的另一个问题,即:
这实际上归结为一个promise响应中多个对象的解析,本机规范中不直接支持这一点,但这里列出了一些方法
因此,如果您实现Bluebird承诺并在那里使用.spread()
方法,那么一切都很好:
var async = require('async'),
Promise = require('bluebird'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var testSchema = new Schema({
name: String
});
var Test = mongoose.model('Test',testSchema,'test');
Promise.promisifyAll(Test);
Promise.promisifyAll(Test.prototype);
async.series(
[
function(callback) {
Test.remove({},callback);
},
function(callback) {
var promise = Test.findOneAndUpdateAsync(
{ "name": "Bill" },
{ "$set": { "name": "Bill" } },
{ "new": true, "upsert": true }
);
promise.spread(function(doc,raw) {
console.log(doc);
console.log(raw);
if ( !raw.lastErrorObject.updatedExisting ) {
console.log( "new document" );
}
callback();
});
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
这当然会返回两个对象,并且您可以一致地访问:
{ _id: 55e14b7af6044f57c8e09a4e, name: 'Bill', __v: 0 }
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e14b7af6044f57c8e09a4e },
value: { _id: 55e14b7af6044f57c8e09a4e, name: 'Bill', __v: 0 },
ok: 1 }
下面是一个完整的列表,展示了正常的行为:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var testSchema = new Schema({
name: String
});
var Test = mongoose.model('Test',testSchema,'test');
async.series(
[
function(callback) {
Test.remove({},callback);
},
function(callback) {
Test.findOneAndUpdate(
{ "name": "Bill" },
{ "$set": { "name": "Bill" } },
{ "new": true, "upsert": true }
).then(function(doc,raw) {
console.log(doc);
console.log(raw);
if ( !raw.lastErrorObject.updatedExisting ) {
console.log( "new document" );
}
callback();
});
}
],
function(err) {
if (err) throw err;
mongoose.disconnect();
}
);
作为记录,本机驱动程序本身没有这个问题,因为响应对象实际上是除了任何错误之外返回的唯一对象:
var async = require('async'),
mongodb = require('mongodb'),
MongoClient = mongodb.MongoClient;
MongoClient.connect('mongodb://localhost/test',function(err,db) {
var collection = db.collection('test');
collection.findOneAndUpdate(
{ "name": "Bill" },
{ "$set": { "name": "Bill" } },
{ "upsert": true, "returnOriginal": false }
).then(function(response) {
console.log(response);
});
});
所以总是这样的:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e12c65f6044f57c8e09a46 },
value: { _id: 55e12c65f6044f57c8e09a46,
number: 55555555,
country: 'US',
token: "XXX",
appInstalled: true,
__v: 0 },
ok: 1 }
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e13bcbf6044f57c8e09a4b },
value: { _id: 55e13bcbf6044f57c8e09a4b, name: 'Bill' },
ok: 1 }
对于承诺使用此功能的人,根据我们的建议,我们可以传递
rawQuery:true
以及其他选项
const filter = { name: 'Will Riker' };
const update = { age: 29 };
await Character.countDocuments(filter); // 0
let res = await Character.findOneAndUpdate(filter, update, {
new: true,
upsert: true,
rawResult: true // Return the raw result from the MongoDB driver
});
res.value instanceof Character; // true
// The below property will be `false` if MongoDB upserted a new
// document, and `true` if MongoDB updated an existing object.
res.lastErrorObject.updatedExisting; /
此查询的结果的格式为
{ lastErrorObject:
{ n: 1,
updatedExisting: false,
upserted: 5e6a9e5ec6e44398ae2ac16a },
value:
{ _id: 5e6a9e5ec6e44398ae2ac16a,
name: 'Will Riker',
__v: 0,
age: 29 },
ok: 1 }
因此,可以在
data.value
处访问该文档。我已尝试查看raw
,但它在最新版本中似乎不再存在(始终未定义)。我还使用Promissions,它只为then(函数(项)提供一个参数…
我最终通过创建自己的createOrUpdate
static解决了这个问题。@MattWay这有点可疑。使用简单的回调可以很好地工作,似乎是关于如何将事情作为承诺传递。我想我会花几分钟来看看这里出了什么问题。根据这一发现,修改只提供了doc(不是raw)。@MattWay关于这个问题的陈述不完全正确。我已经添加了一些关于本机驱动程序方法实际做什么的信息,并用一个工作示例来澄清这一点。这里的问题是驱动程序方法的承诺,而不是功能。