1

Я использую Mongoid в одном из моих рельсов приложения, чтобы для MongoDBMongoDB запрашивая для агрегации с подсчетом нескольких значений

class Tracking 
    include Mongoid::Document 
    include Mongoid::Timestamps 

    field :article_id,  type: String 
    field :action,   type: String # like | comment 
    field :actor_gender, type: String # male | female | unknown 

    field :city,   type: String 
    field :state,   type: String 
    field :country,   type: String 
end 

Здесь я хочу, чтобы захватить запись в этом табличном формате,

article_id | state | male_like_count | female_like_count | unknown_gender_like_count | date 

juhkwu2367 | California | 21 | 7 | 1 | 11-20-2015 
juhkwu2367 | New York | 62 | 23 | 3 | 11-20-2015 
juhkwu2367 | Vermont | 48 | 27 | 3 | 11-20-2015 
juhkwu2367 | California | 21 | 7 | 1 | 11-21-2015 
juhkwu2367 | New York | 62 | 23 | 3 | 11-21-2015 
juhkwu2367 | Vermont | 48 | 27 | 3 | 11-21-2015 

Здесь вход для запроса будет:

article_id 
country 
date range (from and to) 
action (is `like` in this scenario) 
sort_by [ date | state | male_like_count | female_like_count ] 

Это то, что я пытаюсь, ссылаясь в examp ль на https://docs.mongodb.org/v3.0/reference/operator/aggregation/group/

db.trackings.aggregate(
    [ 
     { 
     $group : { 
      _id : { month: { $month: "$created_at" }, day: { $dayOfMonth: "$created_at" }, year: { $year: "$created_at" }, article_id: "$article_id", state: "$state", country: "$country"}, 
      article_id: "$article_id", 
      country: ??, 
      state: "$state", 
      male_like_count: { $sum: ?? } }, 
      female_like_count: { $sum: ?? } }, 
      unknown_gender_like_count: { $sum: ?? } }, 
      date: ?? 
     } 
     } 
    ] 
) 

Так что я должен поставить на месте ?? для сравнения счета по полу и как добавить пункт для sorting_option?

ответ

1

Вы в основном ищете оператора $cond для того, чтобы оценить условия и возвращения, должен ли конкретный счетчик увеличивается на единицу или нет, но есть и некоторые другие понятия агрегации вы здесь отсутствуют:

db.trackings.aggregate([ 
    { "$match": { 
     "created_at": { "$gte": startDate, "$lt": endDate }, 
     "country": "US", 
     "action": "like" 
    }}, 
    { "$group": { 
     "_id": { 
      "date": { 
       "month": { "$month": "$created_at" }, 
       "day": { "$dayOfMonth": "$created_at" }, 
       "year": { "$year": "$created_at" } 
      }, 
      "article_id": "$article_id", 
      "state": "$state" 
     }, 
     "male_like_count": { 
      "$sum": { 
       "$cond": [ 
        { "$eq": [ "$gender", "male" ] }        
        1, 
        0 
       ] 
      } 
     }, 
     "female_like_count": { 
      "$sum": { 
       "$cond": [ 
        { "$eq": [ "$gender", "female" ] }        
        1, 
        0 
       ] 
      } 
     }, 
     "unknown_like_count": { 
      "$sum": { 
       "$cond": [ 
        { "$eq": [ "$gender", "unknown" ] }        
        1, 
        0 
       ] 
      } 
     } 
     }}, 
     { "$sort": { 
     "_id.date.year": 1, 
     "_id.date.month": 1, 
     "_id.date.day": 1, 
     "_id.article_id": 1, 
     "_id.state": 1, 
     "male_like_count": 1, 
     "female_like_count": 1 
     }} 
    ] 
) 

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

Затем все элементы сгруппированы по соответствующей клавише в _id. Это может быть и используется как составное поле, главным образом потому, что все эти значения поля считаются частью ключа группировки, а также для небольшой организации.

Вы также, кажется, спрашиваете в своем выпуске для «отдельных полей» вне самого _id. НЕ ДЕЛАЙТЕ ЭТО. Данные уже есть, поэтому нет смысла копировать его. Вы можете создавать одни и те же вещи за пределами _id через $first в качестве оператора агрегации, или вы даже можете использовать этап $project в конце конвейера для переименования полей. Но это действительно лучше, если вы потеряете привычку, которая, по вашему мнению, вам нужна, поскольку она просто требует времени и пространства для получения ответа.

Если что-то еще, вы, кажется, после «красивой даты» больше всего на свете. Я лично предпочитаю работать с «датой математикой» для большинства манипуляций, и, следовательно, измененный список подходит для Mongoid будет:

Tracking.collection.aggregate([ 
    { "$match" => { 
     "created_at" => { "$gte" => startDate, "$lt" => endDate }, 
     "country" => "US", 
     "action" => "like" 
    }}, 
    { "$group" => { 
     "_id" => { 
      "date" => { 
       "$add" => [ 
        { "$subtract" => [ 
         { "$subtract" => [ "$created_at", Time.at(0).utc.to_datetime ] }, 
         { "$mod" => [ 
          { "$subtract" => [ "$created_at", Time.at(0).utc.to_datetime ] }, 
          1000 * 60 * 60 * 24 
         ]} 
        ]}, 
        Time.at(0).utc.to_datetime 
       ] 
      }, 
      "article_id" => "$article_id", 
      "state" => "$state" 
     }, 
     "male_like_count" => { 
      "$sum" => { 
       "$cond" => [ 
        { "$eq" => [ "$gender", "male" ] }        
        1, 
        0 
       ] 
      } 
     }, 
     "female_like_count" => { 
      "$sum" => { 
       "$cond" => [ 
        { "$eq" => [ "$gender", "female" ] }        
        1, 
        0 
       ] 
      } 
     }, 
     "unknown_like_count" => { 
      "$sum" => { 
       "$cond" => [ 
        { "$eq" =>[ "$gender", "unknown" ] }        
        1, 
        0 
       ] 
      } 
     } 
     }}, 
     { "$sort" => { 
     "_id.date" => 1, 
     "_id.article_id" => 1, 
     "_id.state" => 1, 
     "male_like_count" => 1, 
     "female_like_count" => 1 
     }} 
]) 

Который действительно просто сводится к получению DateTime объекта подходит для использования в качестве аргумента драйвера, который соответствует к дате эпохи и выполнению различных операций. Если обработка $subtract с одной датой BSON и другой будет выдавать числовое значение, которое затем может быть округлено до текущего дня с использованием прикладной математики. Тогда, конечно, при использовании $add с цифровым значением временной метки до даты BSON (опять-таки представляющей эпоху) результат снова будет объектом BSON Date, с конечно скорректированным и округленным значением.

Тогда все дело в том, чтобы применить $sort как этап конвейера агрегации снова, как это было предложено внешнему модификатору.Как и принцип $match, конвейер агрегации может сортироваться в любом месте, но в конце всегда имеет дело с окончательным результатом.

+0

Никогда не думал, что кто-то опубликует ответ так красиво. Большое спасибо @blakes Спасибо за то, что вы нашли решение для прекрасных дат. У меня есть два вопроса: (1) Какая польза от '_id.article_id' в параметрах сортировки? (2) Я считаю, что параметры сортировки работают в порядке сверху вниз, это означает, что сначала он будет сортировать по дате, а затем сортировать по состоянию, а затем male_like_count и женский, как count? правильно. Но если мне не нужен этот уровень сортировки, то передача только нужного ключа должна быть хорошей? – JVK

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