MongoDB агрегатная конвейерная группа

Я пытаюсь построить конвейер, который будет искать документы по определенным критериям и группировать определенные поля, чтобы получить желаемый результат. Структура документа deals является

{
   "_id":"123",
   "status":"New",
   "deal_amount":"5200",
   "deal_date":"2018-03-05",
   "data_source":"API",
   "deal_type":"New Business",
   "account_id":"A1"
},
{
   "_id":"456",
   "status":"New",
   "deal_amount":"770",
   "deal_date":"2018-02-11",
   "data_source":"API",
   "deal_type":"New Business",
   "account_id":"A2"
},
{
   "_id":"885",
   "status":"Old",
   "deal_amount":"4070",
   "deal_date":"2017-09-22",
   "data_source":"API",
   "deal_type":"New Business",
   "account_id":"A2"
},

Имя учетной записи является ссылочным полем. Документ аккаунта выглядит так:

{
   "_id":"A1",
   "name":"Sarah",
},
{
   "_id":"A2",
   "name":"Amber",
},

Конвейер должен искать документы с "статусом" "Новый" и "суммой сделки" более 2000, и он должен группироваться по "имени счета". Трубопровод, который я использовал, идет так

db.deal.aggregate([{
        $match: {
            status: New,
            deal_amount: {
                $gte: 2000,
            }
        }
    }, {
        $group: {
            _id: "$account_name",
        }
    },{
        $lookup:{
            from:"accounts",
            localField:"account_id",
            foreignField:"_id",
            as:"acc",
        }
    }
])

Я хочу показать поля deal_amount, deal_type, deal_date и имя аккаунта только в результате.

Ожидаемый результат:

{
    "_id": "123",
    "deal_amount": "5200",
    "deal_date": "2018-03-05",
    "deal_type": "New Business",
    "account_name": "Sarah"
}, {
    "_id": "885",
    "deal_amount": "4070",
    "deal_date": "2017-09-22",
    "deal_type": "New Business",
    "account_name": "Amber"
},

Нужно ли включать все эти поля, deal_amount, deal_type, deal_date и имя аккаунта, на этапе "группа", чтобы показать результат или есть ли другие способы сделать это. Любая помощь высоко ценится.

4 ответа

Решение

Не уверен, зачем тебе $group этап. Вам просто нужно добавить $project Этап для вывода имени учетной записи из указанной коллекции.

{
  "$project": {
    "deal_amount": 1, 
    "deal_type": 1, 
    "deal_date": 1, 
    "account_name": {"$let":{"vars":{"accl":{"$arrayElemAt":["$acc", 0]}}, in:"$$accl.name}}
   }
}

Пожалуйста, используйте этот запрос.

aggregate([{
        $match: {
            status: "New",
            deal_amount: {
                $gte: 2000,
            }
        }
    },
    {
        $lookup:{
            from:"accounts",
            localField:"account_id",
            foreignField:"_id",
            as:"acc",
        }
    },
    {
        $unwind: {
          path: '$acc',
          preserveNullAndEmptyArrays: true,
        },
      },
      {
      $group: {
            _id: "$acc._id",
            deal_amount: { $first: '$deal_amount' },
            deal_date: { $first: '$deal_date' },
            deal_type: { $first: '$deal_type' },

        }
    }
])

Вы можете сделать это:

1) используя ссылку $$ROOT: ссылка

 { $group : {
            _id : "$author",
            data: { $push : "$$ROOT" }
        }}

2) назначить один параметр

{
        $group: {
            _id: "$account_name",
            deal_amount: { $first: '$deal_amount' },
            deal_date: { $first: '$deal_date' },
            .
            .
        }
    }

Одна вещь, чтобы начать с вашего $gte оператор не работает на строковом поле deal_amount, так что вы можете изменить поле на целые числа или что-то подобное:

// Convert String to Integer
db.deals.find().forEach(function(data) {
    db.deals.update(
            {_id:data._id},
            {$set:{deal_amount:parseInt(data.deal_amount)}});

Затем, чтобы получить только необходимые поля, измените форму документа, используя $project:

db.deals.aggregate([{
        $match: {
            "status": "New",
            "deal_amount" : {
                "$gte" : 2000 
            }
        }
    },     
     {
         $lookup:{
            from:"accounts",
            localField:"account_id",
            foreignField:"_id",
            as:"acc",
        }
    },
     {
        $project: {
            _id: 1, 
            deal_amount: 1, 
            deal_type: 1, 
            deal_date: 1, 
            "account_name": {"$let":{"vars":{"accl":{"$arrayElemAt":["$acc", 0]}}, in:"$$accl.name"}}
        }
    }    
]);

Для меня это произвело:

{ 
    "_id" : "123", 
    "deal_amount" : 5200.0, 
    "deal_date" : "2018-03-05", 
    "deal_type" : "New Business", 
    "account_name" : "Sarah"
}

db.deal.aggregate([{$match: {status: {$eq: 'New'}, deal_amount: {$gte: '2000'}}}, {$group: {_id: {accountName: '$account_id', type: '$deal_type', 'amount': '$deal_amount'}}}])

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