Попытка удалить поддокумент в Mongoose дает мне внутреннюю ошибку мангуста

У меня есть схема (упрощенная):

var Permission = new Schema({
  _id: String, //email address
  role: String //"admin" or "member"
});

var Org = new Schema({
  name: {type: String, index: {unique: true, dropDups: true}, trim: true},
  permissions: [Permission]
});

Пример документа будет выглядеть так:

{
  "name": "My Org",
  "permissions" : [
    {"_id" : "[email protected]", "role" : "admin"},
    {"_id" : "[email protected]", "role" : "member"}
  ]
}

Я пытаюсь удалить одну из строк разрешений, используя команду org.permissions.remove (req.params.email) , как показано в контексте ниже:

exports.removePermissions = function(req, res) {
  var name = req.params.name;
  return Org
    .findOne({name: name})
    .select()
    .exec(function(err, org) {
      if (err) return Org.handleError(res, err);
      if (!org) return Org.handleError(res, new Error("#notfound " + name));
      org.permissions.remove(req.params.email);
      org.save(function(err, org) {
        if (err) return Org.handleError(res, err);
        else return res.send(org);
      });
    });
};

Когда я это сделаю, я получаю следующую ошибку:

TypeError: Cannot use 'in' operator to search for '_id' in [email protected]
    at EmbeddedDocument.Document._buildDoc (/../node_modules/mongoose/lib/document.js:162:27)
    at EmbeddedDocument.Document (/../node_modules/mongoose/lib/document.js:67:20)
    at EmbeddedDocument (/../node_modules/mongoose/lib/types/embedded.js:27:12)
    at new EmbeddedDocument (/../node_modules/mongoose/lib/schema/documentarray.js:26:17)
    at MongooseDocumentArray._cast (/../node_modules/mongoose/lib/types/documentarray.js:62:10)
    at Object.map (native)
    at MongooseDocumentArray.MongooseArray.remove (/../node_modules/mongoose/lib/types/array.js:360:21)
    at model.Org.methods.removePermissions (/../models/org.js:159:20)

Единственное, о чем я могу думать, это то, что Mongoose не поддерживает поля _id, которые не являются ObjectID? Это странно, потому что я использую их в другом месте в своем коде, и он работает нормально (например, org.permissions.id («[email protected].com»)).

Любые предложения очень ценятся!

1
nl ja de

2 ответы

Я не уверен, почему использование remove не работает, но вы можете сделать это атомарно с помощью findOneAndUpdate и $ pull :

exports.removePermissions = function(req, res) {
  var name = req.params.name;
  return Org.findOneAndUpdate(
    {name: name}, 
    {$pull: {permissions: {_id: req.params.email}}},
    function(err, org) {
     //org contains the updated doc
      ...
    });
};
10
добавлено
Опять же - спасибо! Я добавил проблему remove() в список проблем mongoosejs в Github: github.com/LearnBoost/ мангуст/вопросы/1278
добавлено автор Scott Switzer, источник
thx, именно то, что я искал.
добавлено автор zaphod1984, источник
Проблема сейчас исправлена ​​... но она все еще находится в до релизе, 3.6 ветви. хотя это своего рода большая ошибка ... Кажется, я сделал плохой выбор, выбрав мангуст над обычным манго ...
добавлено автор Marius, источник
Спасибо за это, отличный способ сделать операцию атомной. Единственная проблема заключается в том, что вы не узнаете, выполнена ли операция $ pull , т. Е. Если в удаленном DB был удален объект Permission. Для этого уровня проверки ошибок вам нужно сделать это в два этапа с помощью findById , а затем работать с возвращенным org .
добавлено автор Tom Spencer, источник

В соответствии с этим ответом вам нужно вызвать remove() в поддокумент, который вы хотите удалить , а не на весь массив субдокументов.

Итак, измените:

org.permissions.remove(req.params.email);

чтобы:

org.permissions.id(req.params.email).remove();

Этот двухэтапный метод имеет дополнительное преимущество перед ответом, предоставленным @JohnnyHK , в котором вы можете проверить, действительно ли субдокумент существует перед его удалением. Это может быть полезно, если вы хотите отправить ответ 404, указывающий, что поддокумент не существует - насколько мне известно, это невозможно, используя атомный оператор $ pull.

Обратите внимание, что это также будет работать, только если ваш массив субдокументов имеет схему, как показано в вопросе. Если это не так или имеет тип схемы Mixed , коллекция, возвращаемая из базы данных, будет простым массивом, а не массивом с поддержкой Mongoose. Это означает, что функция .id() отсутствует. В этом случае вместо lodash # remove вместо этого:

_.remove(org.permissions, (function(permission) {
  return permission._id.toString() === req.params.email;
}));
3
добавлено
Спасибо, что указали оба варианта! Важно отметить, что документ верхнего уровня должен быть сохранен для продолжения удаления субдокумента. В этом случае с org.save() .
добавлено автор Arian Acosta, источник
pro.js
pro.js
4 675 участник(ов)

Про JavaScript и NodeJS Invite: https://t.me/joinchat/Be4rsT5Rsgq30DHutjxXgA Правила: http://telegra.ph/ru-chat-rules-06-19 Вакансии только с ЗП, не чаще раза в неделю.

Node.js — русскоговорящее сообщество
Node.js — русскоговорящее сообщество
4 160 участник(ов)

Рекомендуем сразу отключить уведомления, чтобы пребывание здесь было комфортным. Правила: https://rudevs.network/ByaMH6un7 См. также: @js_ru, @react_js, @angular_ru, @vuejs_ru, @devops_ru Вакансии и поиск работы: @javascript_jobs и @nodejs_jobs

DBA - русскоговорящее сообщество
DBA - русскоговорящее сообщество
1 345 участник(ов)

Общаемся и обсуждаем темы, посвященные DBA, PostgreSQL, Redis, MongoDB, MySQL, neo4j, riak и т.д. См. также: @devops_ru, @kubernetes_ru, @docker_ru, @nodejs_ru Рекомендуем сразу отключить уведомления, чтобы пребывание здесь было полезным и комфортным.

MongoDB Russian
MongoDB Russian
1 086 участник(ов)

> db.stats() https://combot.org/chat/-1001035023078

Node: русскоязычное сообщество
Node: русскоязычное сообщество
28 участник(ов)

Независимое сообщество node разработчиков на русском языке. Правила: https://node-chat.ru/ Партнеры: @react_ru @ru_vuejs @nuxtjs_ru @ru_docker @nlp_ru