Эквивалентный запрос MongoDb.Linq для условного агрегатора

Я группирую свои данные с помощью MongoDb.Linq следующим образом:

group r1 by new { r1.SupId, r1.SupFullName } into g2
select new
{
    g2.Key.SupFullName,
    Volunteers = from v0 in g2
                 where v0.VolId != g2.Key.SupId
                 select new { v0.VolFullName, v0.VolPeopleCount }
}

То есть я хочу только в Volunteers те, у которых Ids не совпадает с ключом группы. Я ожидал, что драйвер сгенерирует условный $push, но вместо этого он выдает простой:

"$push" : { 
    "VolFullName" : "$VolFullName", 
    "VolPeopleCount" : "$VolPeopleCount" 
}

Теперь, прочитав этот сообщение, я смог преобразовать приведенный выше запрос в следующий:

"$push": {
    "$cond": [
        { "$ne": [ "$VolId", "$SupId" ] },
        { 
            "VolFullName": "$VolFullName",
            "VolPeopleCount": "$VolPeopleCount"
        },
        null
     ]
 }

Что дает мне желаемые результаты. Я хотел бы знать, как, если это возможно, указать драйверу csharp генерировать запрос, подобный приведенному выше. Заранее спасибо!

Обновлено: Следуя предложению @mickl, я смог сгенерировать условный $push (а также условный $sum), но результат оказался не таким, как ожидалось. Предположим, у меня есть следующие документы в моей коллекции:

{ N: "P_1", S: { I: "S_1", FN: "S_1" }, C: { I: "S_1", FN: "S_1" } }
{ N: "P_2", S: { I: "S_1", FN: "S_1" }, C: { I: "S_1", FN: "S_1" } }
{ N: "P_3", S: { I: "S_1", FN: "S_1" }, C: { I: "S_1", FN: "S_1" } }
{ N: "P_4", S: { I: "S_1", FN: "S_1" }, C: { I: "C_2", FN: "C_2" } }
{ N: "P_5", S: { I: "S_1", FN: "S_1" }, C: { I: "C_2", FN: "C_2" } }
{ N: "P_6", S: { I: "S_1", FN: "S_1" }, C: { I: "C_2", FN: "C_2" } }
{ N: "P_7", S: { I: "S_1", FN: "S_1" }, C: { I: "C_3", FN: "C_3" } }
{ N: "P_8", S: { I: "S_1", FN: "S_1" }, C: { I: "C_3", FN: "C_3" } }
{ N: "P_9", S: { I: "S_1", FN: "S_1" }, C: { I: "C_3", FN: "C_3" } }

Здесь N, I, FN, S и C означают имя, идентификатор, полное имя, руководитель и создатель соответственно. Итак, как вы можете видеть, руководитель S_1 наблюдает за каждым документом, создал 3 документа, и есть 6 документов, созданных 2 другими создателями, которые также контролируются S_1. Что я хочу сделать, так это обобщить эти документы по руководителям, а затем по создателям с количеством созданных документов (людей). Итак, мой запрос LINQ выглядит так:

var q = from p in col.AsQueryable()
        group p by new
        {
           SupFullName = p.S.FN,
           SupId = p.S.I,
           CtorFullName = p.C.FN,
           CtorId = p.C.I
        } into g1
        select new
        {
            g1.Key.SupFullName,
            g1.Key.SupId,
            VolFullName = g1.Key.CtorFullName,
            VolId = g1.Key.CtorId,
            VolPeopleCount = g1.LongCount()
        } into r1
        group r1 by new { r1.SupId, r1.SupFullName } into g2
        select new
        {
           g2.Key.SupFullName,
           g2.Key.SupId,
           Volunteers = g2.Select(v => v.VolId != g2.Key.SupId
                           ? new { v.VolId, v.VolFullName, v.VolPeopleCount }
                           : null),
          SupPeopleCount = g2.Select(v => v.VolId == g2.Key.SupId 
                               ? v.VolPeopleCount 
                               : 0).Sum()
        } into r2
        orderby r2.SupPeopleCount descending
        select r2;

Вывод, который дает мне запрос:

Supervisor: S_1, PeopleCount: 0
   Creator: C_3, PeopleCount: 3
   Creator: C_2, PeopleCount: 3
   Creator: S_1, PeopleCount: 3

Это не то, чего я хочу. Правильный вывод будет

Supervisor: S_1, PeopleCount: 3
   Creator: C_3, PeopleCount: 3
   Creator: C_2, PeopleCount: 3

Он генерирует условные агрегаторы следующим образом (если я уберу префикс $_id в условии и оставлю только $SupId, он работает как шарм):

"__agg0": {
      "$push": {
         "$cond": [
             { "$ne": [ "$VolId", "$_id.SupId" ] },
             {
                "VolId": "$VolId",
                "VolFullName": "$VolFullName",
                "VolPeopleCount": "$VolPeopleCount"
             },
             null
         ]
      }
},
"__agg1": {
    "$sum": {
       "$cond": [
           { "$eq": [ "$VolId", "$_id.SupId" ] },
           "$VolPeopleCount",
           NumberLong(0)
       ]
   }
}

Спасибо!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
372
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете запустить Select и использовать тернарный оператор в своем операторе LINQ:

group r1 by new { r1.SupId, r1.SupFullName } into g2
select new
{
    g2.Key.SupFullName,
    Volunteers = g2.Select(x => x.VolId != x.SupId ? new { x.VolFullName, x.VolPeopleCount }: null)  
};

Это преобразуется в следующий конвейер агрегации:

{ 
    "$group" : { 
        "_id" : { "SupId" : "$SupId", "SupFullName" : "$SupFullName" }, 
        "__agg0" : { 
            "$push" : { 
                "$cond" : [
                        { "$ne" : ["$VolId", "$SupId"] }, 
                        { "VolFullName" : "$VolFullName", "VolPeopleCount" : "$VolPeopleCount" }, 
                        null
                    ] 
                } 
            } 
        } 
}, 
{ "$project" : { "SupFullName" : "$_id.SupFullName", "Volunteers" : "$__agg0", "_id" : 0 } }

Привет, спасибо за ваш ответ. Теперь я получаю желаемое условное выражение, но с $_id.SupId в операторе $ne вместо $SupId, что дает результаты, отличные от моего собственного запроса. Это group происходит от другого select другого group. Любая идея, почему это происходит?

dcg 29.05.2019 01:34

@dcg, не могли бы вы отредактировать свой ответ и показать разницу между тем, что вы получаете, и тем, что вы ожидаете? Или, если это что-то, что меняет ожидания от этого вопроса, то, возможно, было бы лучше открыть новый. Спасибо !

mickl 29.05.2019 06:25

Привет, я только что отредактировал свой вопрос. Можешь взглянуть? Спасибо!

dcg 29.05.2019 16:59

@dcg Я думаю, что этот запрос становится немного сложным. Как насчет такого вывода: mongoplayground.net/p/6RePgYMMZUR ?

mickl 29.05.2019 18:45

Мне пришлось прочитать документы, чтобы понять запрос (все еще новичок), и да, этот вывод соответствует моим потребностям. Но... как мне заставить драйвер c# генерировать такой запрос?

dcg 29.05.2019 20:07

Другие вопросы по теме