Trong trường hợp của .findOneAndUpdate()
hoặc bất kỳ .findAndModify()
nào biến thể trình điều khiển cốt lõi cho mongoose, chữ ký gọi lại thực tế có "ba" đối số:
function(err,result,raw)
Đầu tiên là bất kỳ phản hồi lỗi nào, sau đó là tài liệu được sửa đổi hoặc tài liệu gốc tùy thuộc vào các tùy chọn và thứ ba là kết quả ghi của tuyên bố đã ban hành.
Đối số thứ ba đó sẽ trả về dữ liệu giống như sau:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e12c65f6044f57c8e09a46 },
value: { _id: 55e12c65f6044f57c8e09a46,
number: 55555555,
country: 'US',
token: "XXX",
appInstalled: true,
__v: 0 },
ok: 1 }
Với trường nhất quán trong đó là lastErrorObject.updatedExisting
là true/false
tùy thuộc vào kết quả của việc có xảy ra một đợt tăng cường hay không. Lưu ý rằng cũng có một giá trị "nâng cấp" chứa _id
phản hồi cho tài liệu mới khi thuộc tính này false
, nhưng không phải khi nó là true
.
Do đó, bạn sẽ sửa đổi cách xử lý của mình để xem xét điều kiện thứ ba, nhưng điều này chỉ hoạt động với một lệnh gọi lại chứ không phải một lời hứa:
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
}
}
);
Tôi cũng thực sự khuyên bạn nên sử dụng toán tử cập nhật
chứ không phải là các đối tượng thô ở đây, vì một đối tượng thô sẽ luôn ghi đè lên toàn bộ tài liệu, nhưng các toán tử như $set
chỉ ảnh hưởng đến các trường được liệt kê.
Cũng xin lưu ý rằng bất kỳ "đối số truy vấn" phù hợp nào với câu lệnh sẽ được tự động gán trong tài liệu mới miễn là giá trị của chúng là đối sánh chính xác không được tìm thấy.
Giả sử rằng việc sử dụng một lời hứa dường như không trả lại thông tin bổ sung vì lý do nào đó, thì bạn không biết làm thế nào điều này có thể thực hiện được với một lời hứa ngoài việc đặt { new: false}
và về cơ bản khi không có tài liệu nào được trả lại thì đó là một tài liệu mới.
Dù sao thì bạn cũng có tất cả dữ liệu tài liệu dự kiến sẽ được chèn vào, vì vậy không phải là bạn thực sự cần dữ liệu đó được trả về. Trên thực tế, đó là cách các phương thức trình điều khiển gốc xử lý điều này ở cốt lõi và chỉ phản hồi với _id
"uperted" giá trị khi một nâng cấp xảy ra.
Điều này thực sự liên quan đến một vấn đề khác được thảo luận trên trang web này, dưới:
Lời hứa có thể có nhiều đối số với onFulfilled không?
Trường hợp điều này thực sự liên quan đến việc phân giải nhiều đối tượng trong một phản hồi lời hứa, đây là thứ không được hỗ trợ trực tiếp trong cách nói gốc nhưng có những cách tiếp cận được liệt kê ở đó.
Vì vậy, nếu bạn triển khai các hứa hẹn của Bluebird và sử dụng .spread()
ở đó, sau đó mọi thứ đều ổn:
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();
}
);
Tất nhiên, cái nào trả về cả hai đối tượng và bạn có thể truy cập nhất quán sau đó:
{ _id: 55e14b7af6044f57c8e09a4e, name: 'Bill', __v: 0 }
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e14b7af6044f57c8e09a4e },
value: { _id: 55e14b7af6044f57c8e09a4e, name: 'Bill', __v: 0 },
ok: 1 }
Đây là danh sách đầy đủ thể hiện hành vi bình thường:
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();
}
);
Đối với bản ghi, bản thân trình điều khiển gốc không có vấn đề này vì thực tế đối tượng phản hồi là đối tượng duy nhất được trả về ngoài bất kỳ lỗi nào:
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);
});
});
Vì vậy, nó luôn luôn là một cái gì đó như thế này:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e13bcbf6044f57c8e09a4b },
value: { _id: 55e13bcbf6044f57c8e09a4b, name: 'Bill' },
ok: 1 }