Как проверить длину массива при использовании $ push? - PullRequest
0 голосов
/ 28 августа 2018

Я пытаюсь ограничить количество элементов, которые пользователь может добавить в поле массива в одной из моих схем. В настоящее время я добавляю элементы в массив, используя Schema.findOneAndUpdate(); с оператором $push.

Первое, что я попробовал, было решение, данное другим ответом здесь на StackOverflow, а именно: https://stackoverflow.com/a/29418656/6502807 Это решение добавляет функцию проверки к полям в определении схемы. Установив runValidators в true, я получил функцию для запуска с Schema.findOneAndUpdate(). Однако именно в этот момент я наткнулся на следующую проблему. В конце главы «Валидация» в документации по Mongoose говорится:

Кроме того, проверка $ push, $ addToSet, $ pull и $ pullAll не выполняет никакой проверки самого массива, только отдельные элементы массива.

Таким образом, попытка проверить длину массива не сработала при использовании $pull. Она просто каждый раз снабжала функцию проверки пустым массивом, независимо от его фактического содержимого в базе данных.

Затем я попытался использовать pre крючок. Это также было безуспешно. По какой-то причине он не выполнил перехват, даже если runValidators установлено в true. Вот как я определил указанный крючок:

Settings.pre('update', async function (next) {
    if (this.messages.length > MAX_MESSAGES) {
        throw new Error('Too many messages');
    } else {
        next();
    }
});

РЕДАКТИРОВАТЬ: Причина, по которой функция не сработала, была в том, что я использовал findOneAndUpdate вместо update, это исправлено, и функция теперь работает. Однако приведенный выше код решения не работает.

Схема с массивом выглядит так:

const Settings = new mongoose.Schema({
    // A lot more fields not relevant to this question
    messages: {
        type: [{
            type: String
        }]
    }
});

Еще одна вещь, о которой стоит упомянуть, это то, что эти операторы обновления используются вместе с другими опциями. Мне нужно, чтобы оператор update вел себя как обновление или вставка, поэтому мой полный набор параметров выглядит следующим образом:

{
    runValidators: true,
    setDefaultsOnInsert: true,
    upsert: true,
    new: true
}

При выполнении запросов с предварительно установленным хуком, подобным этому, предел массива может быть превышен без какой-либо ошибки проверки.

На данный момент мне интересно, есть ли какой-нибудь разумный способ сделать проверку максимальной длины, подобной этой, без необходимости делать это самостоятельно вне уровня абстракции mongoose.

Я использую Mongoose 5.2.6 на узле v9.11.1 с MongoDB 4.0.0.

Любая помощь очень ценится!

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Ну, если вы используете последнюю версию от mongodb и mongoose, тогда вы можете использовать $expr оператор

const udpate = await db.collection.update(
  { $expr: { $gt: [{"$size": "$messages" }, MAX_MESSAGES] }},
  { update }
)
0 голосов
/ 29 августа 2018

Вы должны быть в состоянии сделать это с помощью крюка pre update. Дело в том, что этот хук по умолчанию не будет give тем обновлением, которое вы используете, чтобы вы могли проверить и т. Д. Вы должны take it через this.getUpdate():

Settings.pre('update', async function (next) {
    var preUpdate = this.getUpdate()
    // now inside of the preUpdate you would have your update being made and should have the array in there on which you can check the length
});

Чтобы дать вам представление о моей схеме тестирования, мне нужно было сделать что-то подобное в обновлении с набором $ :

this.getUpdate().$set.books.length   // gave me 2 which was correct etc

У меня также не было проблем с запуском и нажатием update. Это выглядит очень просто из документации мангуста:

AuthorSchema.pre('update', function(next) {
  console.log('UPDATE hook fired!')
  console.log(this.getUpdate())
  next();
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...