2016-01-31 3 views
5

У меня есть две моделей, одна пользовательМогу ли я использовать заполнение перед агрегатом в мангусте?

userSchema = new Schema({ 
    userID: String, 
    age: Number 
}); 

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

ScoreSchema = new Schema({ 
    userID: {type: String, ref: 'User'}, 
    score: Number, 
    created_date = Date, 
    .... 
}) 

Я хотел бы сделать некоторый запрос/расчет на оценка для некоторых пользователей, отвечающих конкретным требованиям, скажем, я хотел бы рассчитать средний балл для всех пользователей более 20 дней в день.

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

Что-то вроде

Score. 
    populate('userID','age'). 
    aggregate([ 
     {$match: {'userID.age': {$gt: 20}}}, 
     {$group: ...}, 
     {$group: ...} 
    ], function(err, data){}); 

Допустимо ли использовать заселить перед тем агрегате? Или я сначала нахожу все userID, удовлетворяющие требованию, и сохраняю их в массиве, а затем использую $ in для сопоставления документа оценки?

ответ

8

Нет, вы не можете позвонить .populate() перед тем .aggregate(), и есть очень хорошая причина, почему вы не можете. Но есть разные подходы, которые вы можете предпринять.

Метод .populate() работает «на стороне клиента», где базовый код фактически выполняет дополнительные запросы (или, точнее, запрос $in) для «поиска» указанного элемента (ов) из ссылочной коллекции.

В отличие от .aggregate() является «серверной» операцией, поэтому вы в основном не можете манипулировать контентом «клиентская сторона», а затем эти данные доступны для этапов конвейера агрегации позже. Все это должно присутствовать в коллекции, в которой вы работаете.

Более удобный подход можно получить с помощью MongoDB 3.2 и более поздних версий, используя операцию конвейерного конвейера . Кроме того, вероятно, лучше, чтобы справиться с User коллекции в этом случае для того, чтобы сузить выбор:

User.aggregate(
    [ 
     // Filter first 
     { "$match": { 
      "age": { "$gt": 20 } 
     }}, 
     // Then join 
     { "$lookup": { 
      "from": "scores", 
      "localField": "userID", 
      "foriegnField": "userID", 
      "as": "score" 
     }}, 
     // More stages 
    ], 
    function(err,results) { 

    } 
) 

В основном это будет включать в себя новое поле «забьет» в User объекта, как «массив» пунктов что соответствует на «поиск» в другую коллекцию:

{ 
    "userID": "abc", 
    "age": 21, 
    "score": [{ 
     "userID": "abc", 
     "score": 42, 
     // other fields 
    }] 
} 

результат всегда является массив, как общее ожидаемое использованием является «левым соединение» возможным «один ко многим» отношений. Если результат не согласован, это просто пустой массив.

Чтобы использовать контент, просто используйте массив в любом случае. Например, вы можете использовать оператор $arrayElemAt, чтобы просто получить единственный первый элемент массива в любых будущих операциях. И тогда вы можете просто использовать контент, как любое нормальное встроенное поле:

 { "$project": { 
      "userID": 1, 
      "age": 1, 
      "score": { "$arrayElemAt": [ "$score", 0 ] } 
     }} 

Если у вас нет MongoDB 3.2 в наличии, то ваш другой вариант, чтобы обработать запрос ограничен отношениями другой коллекции сначала получить результаты из этой коллекции, а затем использовать $in для фильтрации на второй:

// Match the user collection 
User.find({ "age": { "$gt": 20 } },function(err,users) { 

    // Get id list  
    userList = users.map(function(user) { 
     return user.userID; 
    }); 

    Score.aggregate(
     [ 
      // use the id list to select items 
      { "$match": { 
       "userId": { "$in": userList } 
      }}, 
      // more stages 
     ], 
     function(err,results) { 

     } 
    ); 

}); 

Итак, получив список действительные пользователи из другой коллекции для клиента, а затем подающие ее в другую коллекцию в запросе - это простой способ получить это в предыдущих версиях.

+0

Если userList - это массив объектов, то вам нужно преобразовать их в строки –

+0

вы умный парень, но 'foriegnField' должен быть' foreignField', я думаю. нет большой сделки –

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