Att faktiskt göra vad det verkar som om du säger att du gör är inte en enskild operation, men jag ska gå igenom de delar som krävs för att göra detta eller på annat sätt täcka andra möjliga situationer.
Det du letar efter är delvis den positionella $
operatör. Du behöver en del av din fråga för att också "hitta" elementet i arrayen du vill ha.
db.products.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
"$set": {
"recentviews.$.vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
)
Så $
står för den matchade positionen i arrayen så att uppdateringsdelen vet vilket objekt i arrayen som ska uppdateras. Du kan komma åt enskilda fält i dokumentet i arrayen eller bara ange att hela dokumentet ska uppdateras på den positionen.
db.products.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
"$set": {
"recentviews.$": {
"viewedby": "abc",
"vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
)
Om fälten faktiskt inte ändras och du bara vill infoga ett nytt array-element om exakt samma inte finns, då kan du använda $addToSet
db.products.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
$addToSet:{
"recentviews": {
"viewedby": "abc",
"vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
)
Men om du bara letar efter att "skjuta" till en array med ett singulär nyckelvärde om det inte finns så måste du göra lite mer manuell hantering, genom att först se om elementet i arrayen finns och sedan göra $push
uttalande där det inte gör det.
Du får lite hjälp av mongoosemetoderna att göra detta genom att spåra antalet dokument som påverkas av uppdateringen:
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 enda varningens ord här är att det är lite av en implementeringsändring i writeConcern-meddelandena från MongoDB 2.6 till tidigare versioner. Att vara osäker just nu på hur mongoose API faktiskt implementerar returen av numAffected
argument i callback skillnaden kan betyda något.
I tidigare versioner, även om data du skickade i den första uppdateringen exakt matchade ett befintligt element och det inte krävdes någon verklig ändring, skulle det "modifierade" beloppet returneras som 1
även om ingenting faktiskt uppdaterades.
Från MongoDB 2.6 innehåller skrivproblemsvaret två delar. En del visar det ändrade dokumentet och den andra visar matchningen. Så medan matchningen skulle returneras av frågedelen som matchar ett befintligt element, skulle det faktiska antalet modifierade dokument returneras som 0
om det faktiskt inte krävdes någon förändring.
Så beroende på hur returnumret faktiskt implementeras i mongoose, kan det faktiskt vara säkrare att använda $addToSet
operatör på den inre uppdateringen för att se till att om orsaken till noll påverkade dokument inte bara var att det exakta elementet redan fanns.