Мангуст подсчитывает определенный элемент во встроенном массиве документов

#node.js #mongodb #mongoose #aggregation-framework #mongodb-aggregation

#node.js #mongodb #мангуст #агрегация-фреймворк #mongodb-агрегация

Вопрос:

Я использую mongoose 4.6.3.

У меня есть следующая схема :

 var mongoose = require('mongoose');
var User = require('./User');

var TicketSchema = new mongoose.Schema({
    user : { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
},
{
    timestamps: true
});

var DrawSchema = new mongoose.Schema({
  ...
  max_ticket_per_user : { type : Number, required: true },
  tickets: [TicketSchema]
});

module.exports = mongoose.model('Draw', DrawSchema);
  

Как я могу подсчитать встроенные документы определенного пользовательского объекта (поле пользователя в TicketSchema) в билетах розыгрыша (поле tickets в DrawSchema)?
Я хочу подсчитать билеты пользователя за один розыгрыш.

Было бы лучше изменить дизайн моей схемы?

Спасибо

Ответ №1:

Вы можете использовать структуру агрегации, используя операторы $filter and $size , чтобы получить отфильтрованный массив с элементами, соответствующими идентификатору пользователя и его размеру соответственно, что впоследствии даст вам количество.

Для одиночной выборки рассмотрите возможность добавления $match оператора конвейера в качестве начального шага с запросом _id для фильтрации документов в коллекции.

Для получения желаемого результата рассмотрите возможность запуска следующего конвейера агрегирования:

 Draw.aggregate([
    { "$match": { "_id": drawId } },
    {
        "$project": {
            "ticketsCount": {
                "$size": {
                    "$filter": {
                        "input": "$tickets",
                        "as": "item",
                        "cond": { "$eq": [ "$$item.user", userId ] }
                    }
                }
            }
        }
    }
]).exec(function(err, result) {
    console.log(result);
});
  

Комментарии:

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

2. в ответ я получаю все идентификаторы розыгрышей с их количеством для идентификатора пользователя. Я хочу объединить только один идентификатор рисования

3. @AlexB Вам понадобится конвейерный запрос $ match для фильтрации ваших документов, как я показал в обновлении выше.

4. FWIW, большинство облачных платформ Mongodb, таких как все облачные решения, предоставляемые Heroku, пока не поддерживают версию mongo 3.4 , и, следовательно $filter , команда не будет работать

Ответ №2:

Вы можете передавать .count() глубокие параметры, как и любой другой объект запроса:

 Draw.count({'tickets.user._id' : userId}, console.log);
  

Убедитесь, что переменная userId является ObjectId . Если это строка, сделайте это:

 const ObjectId = require('mongoose').Types.ObjectId;
let userId = new ObjectId(incomingStringId);
  

Комментарии:

1. Это не сработало бы для определенного розыгрыша. Я попробую добавить «_id»: drawId