In het geval van .findOneAndUpdate()
of een van de .findAndModify()
kernstuurprogrammavarianten voor mangoest, de daadwerkelijke callback-handtekening heeft "drie" argumenten:
function(err,result,raw)
De eerste is een eventuele foutreactie, vervolgens het gewijzigde of originele document, afhankelijk van de opties en de derde is een schrijfresultaat van de afgegeven verklaring.
Dat derde argument zou gegevens ongeveer als volgt moeten retourneren:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e12c65f6044f57c8e09a46 },
value: { _id: 55e12c65f6044f57c8e09a46,
number: 55555555,
country: 'US',
token: "XXX",
appInstalled: true,
__v: 0 },
ok: 1 }
Met het consistente veld daarin als lastErrorObject.updatedExisting
ofwel true/false
. zijn afhankelijk van het resultaat of er een upsert is opgetreden. Merk op dat er ook een "upserted" waarde is met de _id
antwoord voor het nieuwe document wanneer deze eigenschap false
is , maar niet als het true
is .
Als zodanig zou je dan je afhandeling aanpassen om rekening te houden met de derde voorwaarde, maar dit werkt alleen met een terugbelverzoek en niet met een belofte:
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
}
}
);
Waar ik je ook sterk zou aanraden om update-operators
te gebruiken in plaats van onbewerkte objecten hier, omdat een onbewerkt object altijd het hele document zal overschrijven, maar operators zoals $set
alleen de vermelde velden beïnvloeden.
Merk ook op dat alle overeenkomende "query-argumenten" met de instructie automatisch worden toegewezen in het nieuwe document, zolang hun waarde een exacte overeenkomst is die niet is gevonden.
Aangezien het gebruik van een belofte om de een of andere reden de aanvullende informatie niet lijkt te retourneren, zie dan niet hoe dit mogelijk is met een andere belofte dan het instellen van { new: false}
en eigenlijk als er geen document wordt geretourneerd, is het een nieuw document.
U hebt alle documentgegevens die naar verwachting toch worden ingevoegd, dus het is niet zo dat u die gegevens toch echt nodig hebt. Het is in feite hoe de native driver-methoden dit in de kern aanpakken en alleen reageren met de "upserted" _id
waarde wanneer er een opstoot optreedt.
Dit komt echt neer op een ander probleem dat op deze site wordt besproken, onder:
Kunnen beloften meerdere argumenten hebben voor onFulfilled?
Waar dit echt neerkomt op de resolutie van meerdere objecten in een belofte-reactie, iets dat niet direct wordt ondersteund in de native specificatie, maar er zijn daar benaderingen vermeld.
Dus als je Bluebird-beloftes implementeert en de .spread()
. gebruikt methode daar, dan is alles in orde:
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();
}
);
Wat natuurlijk beide objecten retourneert en je kunt dan consequent toegang krijgen:
{ _id: 55e14b7af6044f57c8e09a4e, name: 'Bill', __v: 0 }
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e14b7af6044f57c8e09a4e },
value: { _id: 55e14b7af6044f57c8e09a4e, name: 'Bill', __v: 0 },
ok: 1 }
Hier is een volledige lijst die het normale gedrag laat zien:
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();
}
);
Voor de goede orde, het native stuurprogramma zelf heeft dit probleem niet, omdat het responsobject in feite het enige object is dat wordt geretourneerd, afgezien van een fout:
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);
});
});
Dus het is altijd zoiets als dit:
{ lastErrorObject:
{ updatedExisting: false,
n: 1,
upserted: 55e13bcbf6044f57c8e09a4b },
value: { _id: 55e13bcbf6044f57c8e09a4b, name: 'Bill' },
ok: 1 }