Jedynym naprawdę niezawodnym sposobem sprawdzenia, czy zastosowano aktualizację dla czegoś takiego jak $pull
jest zasadniczo sprawdzenie zwróconego dokumentu i sprawdzenie, czy dane, które zamierzałeś $pull
nadal tam jest, czy nie.
To jest dla każdego z "findAndUpdate"
różnych działań i jest ku temu uzasadniony powód, a także fakt, że zwykły .update()
faktycznie "rzetelnie" powie ci, czy modyfikacja została faktycznie wykonana.
Aby przejść przez przypadki:
Sprawdź zwróconą zawartość
Zasadniczo polega to na przejrzeniu tablicy w zwróconym dokumencie, aby sprawdzić, czy to, o co prosiliśmy, rzeczywiście tam jest:
var pullId = "5961de06ea264532c684611a";
Office.findByIdAndUpdate(1,
{ "$pull": { "branches": { "_id": pullId } } },
{ "new": true }
).then(office => {
// Check if the supplied value is still in the array
console.log(
"Still there?: %s",
(office.branches.find( b => b._id.toHexString() === pullId))
? true : false
);
}).catch(err => console.error(err))
Używamy .toHexString()
w celu porównania rzeczywistej wartości z ObjectId
ponieważ JavaScript po prostu nie robi "równości" z "obiektami". Możesz sprawdzić zarówno "lewo", jak i "prawo", jeśli dostarczasz coś, co zostało już "oddane" do ObjectId
wartość, ale w tym przypadku wiemy, że drugie wejście to „ciąg”.
Wystarczy użyć .update(), „Jest niezawodny”
Drugi przypadek do rozważenia stawia pod znakiem zapytania, czy i tak „naprawdę potrzebujesz” zwróconych zmodyfikowanych danych. Ponieważ .update()
metody, niezawodnie zwróci wynik informujący, czy coś zostało faktycznie zmodyfikowane:
Office.update(
{ "_id": 1 },
{ "$pull": { "branches": { "_id": pullId } } },
).then(result => {
log(result);
}).catch(err => console.error(err))
Gdzie wynik
tutaj będzie wyglądać tak:
{
"n": 1,
"nModified": 1, // <--- This always tells the truth, and cannot lie!
"opTime": {
"ts": "6440673063762657282",
"t": 4
},
"electionId": "7fffffff0000000000000004",
"ok": 1
}
I w którym nModified
jest „prawdziwym” wskaźnikiem tego, czy coś jest „aktualnie zaktualizowane”. Dlatego jeśli jest to 1
następnie $pull
faktycznie miał wpływ, ale kiedy 0
nic nie zostało faktycznie usunięte z tablicy i nic nie zostało zmodyfikowane.
Dzieje się tak, ponieważ metoda faktycznie wykorzystuje zaktualizowane API, które daje wiarygodne wyniki wskazujące na rzeczywiste modyfikacje. To samo dotyczy czegoś takiego jak $set
który w rzeczywistości nie zmienił wartości, ponieważ podana wartość była równa wartości, która już istniała w dokumencie.
znajdź i zmodyfikuj kłamstwa!
Innym przypadkiem, o którym możesz pomyśleć, gdy uważnie przyjrzysz się dokumentacji, jest sprawdzenie „surowego wyniku” i sprawdzenie, czy dokument został zmodyfikowany, czy nie. W specyfikacji znajduje się odpowiedni wskaźnik.
Problem polega (poza tym, że wymaga więcej pracy z Obietnicami), że wynik nie jest w rzeczywistości zgodny z prawdą:
var bogusId = "5961de06ea264532c684611a"; // We know this is not there!
Promise((resolve,reject) => {
Office.findByIdAndUpdate(1,
{ "$pull": { "branches": { "_id": bogusId } } },
{ "new": true, "passRawResult" },
(err,result,raw) => { // We cannot pass multiple results to a Promise
if (err) reject(err);
resolve({ result, raw }); // So we wrap it!
}
)
})
.then(response => log(response.raw))
.catch(err => console.error(err));
Problem polega na tym, że nawet jeśli „wiemy”, że to nie powinno się zmieniać, odpowiedź mówi inaczej:
{
"lastErrorObject": {
"updatedExisting": true,
"n": 1 // <--- LIES! IT'S ALL LIES!!!
},
"value": {
"_id": 1,
"name": "My Office",
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961de06ea264532c6846118"
}
],
"__v": 0
},
"ok": 1,
"_kareemIgnore": true
}
Więc nawet po tych wszystkich pracach, aby uzyskać „trzeci” argument z odpowiedzi zwrotnej, nadal nie otrzymaliśmy poprawnych informacji o aktualizacji.
Podsumowanie
Więc jeśli chcesz „niezawodnie” zrobić to za pomocą jednego żądania (a nie możesz niezawodnie rób to z wieloma żądaniami, ponieważ dokument może się zmienić pomiędzy! ) masz dwie opcje:
-
Sprawdź zwrócony dokument, aby sprawdzić, czy dane, które chciałeś usunąć, nadal tam są.
-
Zapomnij o zwracaniu dokumentu i zaufaj, że
.update()
zawsze mówi ci "prawdę";)
To, którego z nich użyjesz, zależy od wzorca użytkowania aplikacji, ale są to dwa różne sposoby zwracania „wiarygodnego” wyniku.
Część aukcji
Aby mieć pewność, oto lista, która przechodzi przez wszystkie przykłady i pokazuje, co faktycznie zwracają:
const async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
mongoose.connect('mongodb://localhost/test');
const branchesSchema = new Schema({
address: String,
isPrincipal: Boolean
});
const officeSchema = new Schema({
_id: Number,
name: String,
branches: [branchesSchema]
},{ _id: false });
const Office = mongoose.model('Office', officeSchema);
function log(data) {
console.log(JSON.stringify(data,undefined,2))
}
const testId = "5961a56d3ffd3d5e19c61610";
async.series(
[
// Clean data
(callback) =>
async.each(mongoose.models,(model,callback) =>
model.remove({},callback),callback),
// Insert some data and pull
(callback) =>
async.waterfall(
[
// Create and demonstrate
(callback) =>
Office.create({
_id: 1,
name: "My Office",
branches: [
{
address: "Some street, that avenue",
isPrincipal: true
},
{
address: "Another address",
isPrincipal: false
},
{
address: "Third address",
isPrincipal: false
}
]
},callback),
// Demo Alternates
(office,callback) =>
async.mapSeries(
[true,false].map((t,i) => ({ t, branch: office.branches[i] })),
(test,callback) =>
(test.t)
? Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": test.branch._id } } },
{ "new": true , "passRawResult": true },
(err,result,raw) => {
if (err) callback(err);
log(result);
log(raw);
callback();
})
: Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": test.branch._id } } },
{ "new": true } // false here
).then(result => {
log(result);
console.log(
"Present %s",
(result.branches.find( b =>
b._id.toHexString() === test.branch._id.toHexString() ))
? true : false
);
callback();
}).catch(err => callback(err)),
callback
)
],
callback
),
// Find and demonstate fails
(callback) =>
async.waterfall(
[
(callback) => Office.findOne({},callback),
(office,callback) =>
async.eachSeries([true,false],(item,callback) =>
(item)
? Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": testId } } },
{ "new": true, "passRawResult": true },
(err,result,raw) => {
if (err) callback(err);
log(result);
log(raw);
callback();
}
)
: Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": testId } } },
{ "new": true }
).then(result => {
console.log(result);
console.log(
"Present %s",
(result.branches.find( b =>
b._id.toHexString() === office.branches[0]._id.toHexString()))
? true : false
);
callback();
})
.catch(err => callback(err)),
callback)
],
callback
),
// Demonstrate update() modified shows 0
(callback) =>
Office.update(
{},
{ "$pull": { "branches": { "_id": testId } } }
).then(result => {
log(result);
callback();
})
.catch(err => callback(err)),
// Demonstrate wrapped promise
(callback) =>
Office.findOne()
.then(office => {
return new Promise((resolve,reject) => {
Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": testId } } },
{ "new": true, "passRawResult": true },
(err,result,raw) => {
if (err) reject(err);
resolve(raw)
}
);
})
})
.then(office => {
log(office);
callback();
})
.catch(err => callback(err))
],
(err) => {
if (err) throw err;
mongoose.disconnect();
}
);
A wynik, który generuje:
Mongoose: offices.remove({}, {})
Mongoose: offices.insert({ _id: 1, name: 'My Office', branches: [ { address: 'Some street, that avenue', isPrincipal: true, _id: ObjectId("5961e5211a73e8331b44d74b") }, { address: 'Another address', isPrincipal: false, _id: ObjectId("5961e5211a73e8331b44d74a") }, { address: 'Third address', isPrincipal: false, _id: ObjectId("5961e5211a73e8331b44d749") } ], __v: 0 })
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961e5211a73e8331b44d74b") } } }, { new: true, passRawResult: true, upsert: false, remove: false, fields: {} })
{
"_id": 1,
"name": "My Office",
"__v": 0,
"branches": [
{
"address": "Another address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d74a"
},
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
]
}
{
"lastErrorObject": {
"updatedExisting": true,
"n": 1
},
"value": {
"_id": 1,
"name": "My Office",
"branches": [
{
"address": "Another address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d74a"
},
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
],
"__v": 0
},
"ok": 1,
"_kareemIgnore": true
}
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961e5211a73e8331b44d74a") } } }, { new: true, upsert: false, remove: false, fields: {} })
{
"_id": 1,
"name": "My Office",
"__v": 0,
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
]
}
Present false
Mongoose: offices.findOne({}, { fields: {} })
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, { new: true, passRawResult: true, upsert: false, remove: false, fields: {} })
{
"_id": 1,
"name": "My Office",
"__v": 0,
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
]
}
{
"lastErrorObject": {
"updatedExisting": true,
"n": 1
},
"value": {
"_id": 1,
"name": "My Office",
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
],
"__v": 0
},
"ok": 1,
"_kareemIgnore": true
}
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, { new: true, upsert: false, remove: false, fields: {} })
{ _id: 1,
name: 'My Office',
__v: 0,
branches:
[ { address: 'Third address',
isPrincipal: false,
_id: 5961e5211a73e8331b44d749 } ] }
Present true
Mongoose: offices.update({}, { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, {})
{
"n": 1,
"nModified": 0,
"opTime": {
"ts": "6440680872013201413",
"t": 4
},
"electionId": "7fffffff0000000000000004",
"ok": 1
}
Mongoose: offices.findOne({}, { fields: {} })
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, { new: true, passRawResult: true, upsert: false, remove: false, fields: {} })
{
"lastErrorObject": {
"updatedExisting": true,
"n": 1
},
"value": {
"_id": 1,
"name": "My Office",
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
],
"__v": 0
},
"ok": 1,
"_kareemIgnore": true
}