W przypadku .findOneAndUpdate()
lub dowolny z .findAndModify()
podstawowe warianty sterownika dla mangusty, rzeczywista sygnatura wywołania zwrotnego ma „trzy” argumenty:
function(err,result,raw)
Pierwszym jest dowolna odpowiedź na błąd, następnie zmodyfikowany lub oryginalny dokument w zależności od opcji, a trzeci jest wynikiem zapisu wydanego oświadczenia.
Ten trzeci argument powinien zwracać dane w podobny sposób:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e12c65f6044f57c8e09a46 },
value: { _id: 55e12c65f6044f57c8e09a46,
number: 55555555,
country: 'US',
token: "XXX",
appInstalled: true,
__v: 0 },
ok: 1 }
Ze spójnym polem tam jako lastErrorObject.updatedExisting
będąc true/false
w zależności od wyniku tego, czy wystąpiło upsert. Zauważ, że istnieje również „przesunięta” wartość zawierająca _id
odpowiedź dla nowego dokumentu, gdy ta właściwość ma wartość false
, ale nie wtedy, gdy jest true
.
W związku z tym zmodyfikujesz obsługę, aby uwzględnić trzeci warunek, ale działa to tylko z wywołaniem zwrotnym, a nie z obietnicą:
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
}
}
);
W przypadku, gdy sugerowałbym również użycie operatorów aktualizacji
zamiast surowych obiektów tutaj, ponieważ surowy obiekt zawsze nadpisze cały dokument, ale operatory takie jak $set
wpływa tylko na wymienione pola.
Należy również zauważyć, że wszelkie pasujące „argumenty zapytania” do instrukcji są automatycznie przypisywane w nowym dokumencie, o ile ich wartość jest dokładnym dopasowaniem, które nie zostało znalezione.
Biorąc pod uwagę, że użycie obietnicy z jakiegoś powodu nie zwraca dodatkowych informacji, nie zobacz, jak jest to możliwe z obietnicą inną niż ustawienie { new: false}
i w zasadzie, gdy żaden dokument nie zostanie zwrócony, to jest nowy.
Masz wszystkie dane dokumentu, które i tak mają zostać wstawione, więc nie jest tak, że i tak naprawdę potrzebujesz tych danych. W rzeczywistości jest to sposób, w jaki metody natywnego sterownika obsługują to w rdzeniu i odpowiadają tylko za pomocą „przesuniętego” _id
wartość, gdy wystąpi upsert.
To naprawdę sprowadza się do innego problemu omawianego na tej stronie, pod:
Czy obietnice mogą mieć wiele argumentów do spełnienia?
Gdzie tak naprawdę sprowadza się to do rozwiązania wielu obiektów w odpowiedzi obietnicy, co nie jest bezpośrednio obsługiwane w natywnej specyfikacji, ale są tam wymienione podejścia.
Więc jeśli zaimplementujesz obietnice Bluebird i użyjesz .spread()
metoda tam, to wszystko jest w porządku:
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();
}
);
Który oczywiście zwraca oba obiekty i możesz uzyskać dostęp do nich konsekwentnie:
{ _id: 55e14b7af6044f57c8e09a4e, name: 'Bill', __v: 0 }
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e14b7af6044f57c8e09a4e },
value: { _id: 55e14b7af6044f57c8e09a4e, name: 'Bill', __v: 0 },
ok: 1 }
Oto pełna lista pokazująca normalne zachowanie:
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();
}
);
Dla przypomnienia, sam sterownik natywny nie ma tego problemu, ponieważ obiekt odpowiedzi jest w rzeczywistości tylko obiektem zwróconym poza jakimkolwiek błędem:
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);
});
});
Więc zawsze jest mniej więcej tak:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e13bcbf6044f57c8e09a4b },
value: { _id: 55e13bcbf6044f57c8e09a4b, name: 'Bill' },
ok: 1 }