Mongodb группа и сортировка - PullRequest
23 голосов
/ 01 июля 2011

Как я могу перевести следующий Sql запрос для Mongo?:

select a,b,sum(c) csum from coll where active=1 group by a,b order by a

Есть ли способ выполнить запрос группы и сортировки с Mongo?

Ответы [ 9 ]

17 голосов
/ 23 марта 2014

Вдохновленный этим примером на веб-сайте Монго.

ОБЩИЕ КУЛЬТУРНЫЕ ДАННЫЕ:

> db.stack.insert({a:1,b:1,c:1,active:1})
> db.stack.insert({a:1,b:1,c:2,active:0})
> db.stack.insert({a:1,b:2,c:3,active:1})
> db.stack.insert({a:1,b:2,c:2,active:0})
> db.stack.insert({a:2,b:1,c:3,active:1})
> db.stack.insert({a:2,b:1,c:10,active:1})
> db.stack.insert({a:2,b:2,c:10,active:0})
> db.stack.insert({a:2,b:2,c:5,active:1})

MONGO QUERY:

> db.stack.aggregate(
... {$match:{active:1}},
... {$group:{_id:{a:"$a", b:"$b"}, csum:{$sum:"$c"}}},
... {$sort:{"_id.a":1}})

РЕЗУЛЬТАТ:

{"result" : [
    {"_id" : {"a" : 1,"b" : 2},"csum" : 3},
    {"_id" : {"a" : 1,"b" : 1},"csum" : 1},
    {"_id" : {"a" : 2,"b" : 2},"csum" : 5},
    {"_id" : {"a" : 2,"b" : 1},"csum" : 13}
],"ok" : 1}

(ПРИМЕЧАНИЕ: я немного переформатировал результат оболочки, чтобы он был более читабельным)

16 голосов
/ 13 марта 2013

Используя агрегатную среду, вы можете сделать следующее:

db.coll.aggregate({ 
    $group: { 
        _id: "$a", 
        countA: { $sum: 1}, 
        sumC:{ $sum: "$c"}, 
    },
    $sort:{a:1}
});

Однако, если у вас слишком много данных, вы можете получить следующее сообщение об ошибке:

{
    "errmsg" : "exception: aggregation result exceeds maximum document size (16MB)",
    "code" : 16389,
    "ok" : 0
}

Подробнеео переводе SQL в Mongo здесь: http://docs.mongodb.org/manual/reference/sql-aggregation-comparison/

4 голосов
/ 25 июля 2016

API агрегации mongodb, похоже, изменился.Теперь вы должны сделать

db.coll.aggregate([
  {
     $group: { 
        _id: "$a", 
        countA: { $sum: 1}, 
        sumC:{ $sum: "$c"}, 
     }
  },
  {
    $sort:{a:1}
  }
])

Обратите внимание на синтаксис Array для аргумента aggregate ().Вы также добавили бы в качестве элементов этого массива ссылку $ match, $ limit и т. Д.

4 голосов
/ 13 декабря 2012

Я построил гистограмму, и то, что я сделал с версией 2.2.2, было:

answer = db.coll.group(...)
db.histo.insert(answer)
db.histo.find().sort({ field: 1 })

На данный момент, если вам это не нужно, просто db.histo.drop().

Вы также можете избежать переменной и сделать:

db.histo.insert(db.coll.group(...))
db.histo.ensureIndex({ field: 1 })
1 голос
/ 04 сентября 2011
db.coll.group(
       {key: { a:true, b:true },
        cond: { active:1 },
        reduce: function(obj,prev) { prev.csum += obj.c; },
        initial: { csum: 0 }
        });

Вы можете выполнить его в MongoDB

1 голос
/ 01 июля 2011

См

http://www.mongodb.org/display/DOCS/Aggregation http://www.mongodb.org/display/DOCS/SQL+to+Mongo+Mapping+Chart

или скомбинируйте его, используя map-limit.

0 голосов
/ 05 мая 2019

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

Запрос:

db.getCollection('orders').aggregate([
    {$match:{
        tipo: {$regex:"[A-Z]+"}
        }
    },
    {$group:
        { 
            _id:{
                codigo:"1",
                fechaAlta:{$substr:["$fechaAlta",0,10]},
            },
            total:{$sum:1}
        }
    },
    {$sort:
        {"_id":1}
    },
    {$group:
        {
            _id:"$_id.codigo",
            fechasAltas:
            {
                $push:
                {
                    fechaAlta:"$_id.fechaAlta",
                    total:"$total"
                }
            },
            totalGeneral:{$sum:"$total"}
        }
    }
]); 

Ответ:

{
"_id" : "1",
"fechasAltas" : [ 
    {
        "fechaAlta" : "1940-01-01",
        "total" : 13.0
    }, 
    {
        "fechaAlta" : "2007-05-14",
        "total" : 115.0
    }, 
    {
        "fechaAlta" : "2008-09-30",
        "total" : 58.0
    }, 

    .
    .
    .
],
"totalGeneral" : 50620.0
}       
0 голосов
/ 12 марта 2019

Добавление к предыдущим ответам, если вы хотите отсортировать по сумме (результату совокупности), а не по фактическому столбцу, вы можете сделать это:

db.your_collection.aggregate([
    {
        $group: {_id: "$your_document_name", count: {$sum: 1}}
    }, 
    {
        $sort: {"count":-1}
    }
])

Это будет эквивалентноследующий синтаксис стандартного SQL-кода:

select col_a, count(col_a) as b
from table
group by col_a
order by b desc
0 голосов
/ 21 апреля 2012

До тех пор, пока в MongoDB 2.1 не будет выпущен Aggregation Framework , вызов группы, как в этот ответ , будет довольно медленным, так как он использует JavaScript-часть БД.

Вы можете использовать более быстрый подход для подсчета групп:

var res = [];
for( var cur_a = db.coll.distinct('a'); cur_a.hasNext(); ) {
  var a = cur_a.next();
  for( var cur_b = db.coll.distinct('b'); cur_b.hasNext(); ) {
    var b = cur_b.next();
    res.push({ 'a': a, 'b' : b 'count': db.coll.count({'a':a,'b':b})}
  }
}

Это будет быстрее, если у вас есть индексы на a и b

db.coll.ensureIndex({'a':1,'b':1})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...