2015-05-19 2 views
5

Я использую средний стек. Мне это неудобно, и я попал в рассол. Я видел примеры обновления записей с помощью set или push, но поскольку я пытаюсь обновить один объект json внутри json-объекта в массиве объектов json, у меня возникают проблемы.MongoDB. Как обновить свойство json внутри массива

Рассмотрим следующую схему

token: { 
    type: String, 
    required: "FB access token required." 
}, 
fbId: { 
    type: String, 
    required: "FB id required.", 
    unique: true 
}, 
accounts: { 
    type: Array, 
    default: [] 
} 

Мои счета массив состоит из объектов JSON, каждый из которых выглядят следующим образом:

{ 
    "name": "some name", 
    "credentials": { 
     "username": "some username", 
     "password": "some password" 
} 

Я пытаюсь обновить аккаунты каждый раз, когда пользователь добавляет новый. Так что в этом случае я могу использовать $ push просто отлично. Но я не хочу дублировать имена, и $ push здесь не работает. Поэтому я попытался использовать $ set, но $ set не вставляет объекты с новыми именами в учетные записи. Поэтому я попытался использовать upsert: true с $ set, но теперь у меня возникают повторяющиеся ошибки.

Вот пример, где я пытаюсь индексировать имя в аккаунтах. Я предполагаю, что я как-то накручиваю свой запрос.

var name = "some name"; 
var fbId = "some fb Id"; 
var token = "some token"; 
var username = "some other username"; 
var password = "some other password"; 

var query = { 
    fbId: fbId, 
    token: token, 
    "accounts.name":name 
}; 
var update = { 
    $set: { 
     accounts: [{ 
      name: name, 
      credentials: { 
       username: username, 
       password: password 
      } 
     }] 
    } 

}; 
var options = { 
    upsert: true 
}; 
User.update(query, update, options, 
    function (err, numberAffected, rawResponse) { 
     //handle it 
    }); 
); 

Подводя итог моему вопросу, разумно ли мне подумать, что я могу обновить его одним звонком, и если да, то как? Или мне нужно найти объект, заменить его значения и затем вставить его в базу данных?

ответ

4

Вы можете использовать оператор обновления $ массива:

var query = { 
    fbId: fbId, 
    token: token, 
    "accounts.name":name 
}; 
var update = { 
    $set: { 
     "accounts.$": [{  //The $ operator goes into the update object 
      name: name, 
      credentials: { 
       username: username, 
       password: password 
      } 
     }] 
    } 
}; 

Согласно documentation:

Позиционные $ оператор идентифицирует элемент в массиве обновления без явно указывая положение элемента в массиве .

EDIT:

В соответствии с этим MongoDB JIRA page, используя upsert с позиционным оператором $ все еще остается открытым вопрос.

Я искал вокруг и нашел возможное решение, которое, к сожалению, побеждает вашу цель достижения этого одним звонком. Вы можете найти here.

Чтобы суммировать этот ответ, вам нужно будет сначала отправить запрос на обновление без флага upsert. Затем проверьте ответ, чтобы узнать, обновлен ли документ, если нет (это означает, что такой поддокумент не существует), отправьте другой запрос с оператором $push, чтобы вставить новый поддокумент в массив.

+0

Получение следующего сообщения об ошибке. Оператор позиционирования не нашел соответствия, необходимого для запроса. Unexpanded update: accounts. $ – zafrani

+0

О, вам нужно установить флаг upsert в true. – ZeMoon

+0

Это было. Когда я комментирую флаг upsert, я не получаю никаких ошибок, но он также ничего не обновляет. – zafrani

0

Если $push работает на вас, но вы хотите избежать добавления дубликатов в массив, попробуйте $addToSet. Он добавит значение к массиву, пока это значение еще не находится в нем. Ознакомьтесь с документацией $addToSet.

Update

Ваш оригинальный пост:

Я пытаюсь обновить аккаунты каждый раз, когда пользователь добавляет новый. Так что в этот случай я могу использовать $ push просто отлично. Но я не хочу дублировать имена, и $ push здесь.

var uniqueAccount = { 
    name:'unique account', 
    credentials: { 
    username:'new username', 
    password:'some secret password' 
    } 
}; 

db.accounts.update({fbId: fbId, token: token}, 
    {accounts: {$addToSet: uniqueAccount}}); 
+0

Да, но если он уже существует, он не обновит его. – zafrani

Смежные вопросы