Ответ 1
На самом деле делать то, что кажется, что вы говорите, что вы делаете, не является особой операцией, но я пройду части, необходимые для этого, или иным образом рассмотрю другие возможные ситуации.
То, что вы ищете, является частью оператора positional $
. Вам потребуется часть вашего запроса, чтобы также "найти" элемент требуемого массива.
db.products.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
"$set": {
"recentviews.$.vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
)
Таким образом, $
обозначает совпадающую позицию в массиве, поэтому часть обновления знает, какой элемент в массиве обновляется. Вы можете получить доступ к отдельным полям документа в массиве или просто указать весь документ для обновления в этой позиции.
db.products.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
"$set": {
"recentviews.$": {
"viewedby": "abc",
"vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
)
Если поля фактически не изменяются, и вы просто хотите вставить новый элемент массива, если он не существует точно так же, вы можете использовать $addToSet
db.products.update(
{
"_id": ObjectId("536c55bf9c8fb24c21000095"),
"recentviews.viewedby": "abc"
},
{
$addToSet:{
"recentviews": {
"viewedby": "abc",
"vieweddate": ISODate("2014-05-09T04:12:47.907Z")
}
}
)
Однако, если вы просто ищете "толкание" к массиву с помощью значения исключительного ключа, если этого не существует, вам нужно сделать еще одну ручную обработку, сначала увидев, существует ли элемент в массиве, а затем $push
, где это не так.
Вы получаете некоторую помощь от методов mongoose при этом, отслеживая количество документов, на которые влияет обновление:
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) {
}
);
}
}
);
Единственное слово предостережения здесь заключается в том, что в сообщениях writeConcern от MongoDB 2.6 до более ранних версий есть немного изменений в реализации. Непонятно, как теперь API-интерфейс mongoose реализует возврат аргумента numAffected
в обратном вызове, что разница может означать что-то.
В предыдущих версиях, даже если данные, отправленные в исходном обновлении, точно соответствовали существующему элементу, и не было никаких реальных изменений, тогда "измененная" сумма будет возвращена как 1
, хотя ничего не было фактически обновлено.
От MongoDB 2.6 ответ на реакцию на запись состоит из двух частей. Одна часть показывает измененный документ, а другой показывает совпадение. Поэтому, пока совпадение будет возвращено частью запроса, соответствующей существующему элементу, фактический измененный счетчик документов будет возвращаться как 0
, если на самом деле не было никаких изменений.
Таким образом, в зависимости от того, как действительно возвращается номер возврата в мангусте, на самом деле безопаснее использовать оператор $addToSet
. это внутреннее обновление, чтобы убедиться, что если причина для документов с нулевым воздействием была не только в том, что точный элемент уже существовал.