At gøre, hvad det ser ud som om, du siger, du gør, er ikke en enkelt operation, men jeg vil gennemgå de dele, der kræves for at gøre dette eller på anden måde dække andre mulige situationer.
Det, du leder efter, er delvist den positionelle $
operatør. Du skal bruge en del af din forespørgsel for også at "finde" det element i det array, du ønsker.
db.products.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
"$set": {
"recentviews.$.vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
)
Så $
står for den matchede position i arrayet, så opdateringsdelen ved, hvilket element i arrayet der skal opdateres. Du kan få adgang til individuelle felter i dokumentet i arrayet eller blot angive, at hele dokumentet skal opdateres på den position.
db.products.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
"$set": {
"recentviews.$": {
"viewedby": "abc",
"vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
)
Hvis felterne faktisk ikke ændres, og du blot vil indsætte et nyt array-element, hvis det nøjagtige samme ikke eksisterer, så kan du bruge $addToSet
db.products.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
$addToSet:{
"recentviews": {
"viewedby": "abc",
"vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
)
Men hvis du bare leder efter at "skubbe" til et array med en enkelt nøgleværdi, hvis den ikke eksisterer, skal du gøre noget mere manuel håndtering ved først at se om elementet i arrayet eksisterer og derefter lave $push
erklæring, hvor den ikke gør det.
Du får lidt hjælp fra mongoose-metoderne til at gøre dette ved at spore antallet af dokumenter, der er påvirket af opdateringen:
Product.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
"$set": {
"recentviews.$": {
"viewedby": "abc",
"vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
},
function(err,numAffected) {
if (numAffected == 0) {
// Document not updated so you can push onto the array
Product.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095")
},
{
"$push": {
"recentviews": {
"viewedby": "abc",
"vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
},
function(err,numAffected) {
}
);
}
}
);
Det eneste advarselsord her er, at der er lidt af en implementeringsændring i writeConcern-meddelelserne fra MongoDB 2.6 til tidligere versioner. Er lige nu usikker på, hvordan mongoose API'en faktisk implementerer returneringen af numAffected
argument i tilbagekaldet kan forskellen betyde noget.
I tidligere versioner, selvom de data, du sendte i den indledende opdatering, matchede nøjagtigt et eksisterende element, og der ikke var nogen reel ændring påkrævet, ville det "modificerede" beløb blive returneret som 1
selvom intet faktisk blev opdateret.
Fra MongoDB 2.6 indeholder skrivebekymringssvaret to dele. Den ene del viser det ændrede dokument, og den anden viser matchen. Så mens matchningen ville blive returneret af forespørgselsdelen, der matcher et eksisterende element, ville det faktiske ændrede dokumentantal returnere som 0
hvis der faktisk ikke var behov for ændringer.
Så afhængigt af hvordan returnummeret faktisk er implementeret i mongoose, kan det faktisk være mere sikkert at bruge $addToSet
operatør på den indre opdatering for at sikre, at hvis årsagen til nul berørte dokumenter ikke bare var, at det nøjagtige element allerede eksisterede.