Tengo una colección MongoDB como esta:

{ "_id" : ObjectId("5a017ee061313781045889ea"),  "device_id" : "1232213",   "value" : "23233", "pubtime" : ISODate("2017-11-07T09:37:37.006Z") }
{ "_id" : ObjectId("5a017f7b61313781045889eb"),  "device_id" : "1111",   "value" : "23233", "pubtime" : ISODate("2017-11-07T09:40:11.204Z") }
{ "_id" : ObjectId("5a017fdd61313781045889ec"),  "device_id" : "12222",   "value" : "23233", "pubtime" : ISODate("2017-11-07T09:41:49.452Z") }
{ "_id" : ObjectId("5a017ff561313781045889ed"),  "device_id" : "1232213",   "value" : "23233", "pubtime" : ISODate("2017-11-07T09:42:13.658Z") }

Quiero diferenciarlo por "device_id" Y ordenarlo por "pubtime".

Sé que Golang podría usar tubería para hacerlo. Pero no sé cómo hacerlo. Lo que probé:

o1 := bson.M{"_id": bson.M{"device_id": "$device_id"}}

o2 := bson.M{"pubtime": bson.M{"$last": "$pubtime"}}
o3 := bson.M{"$group": []bson.M{o1, o2}}
pipe := c.Pipe([]bson.M{o3})
var result = []bson.M{}
_ = pipe.All(&result)
fmt.Println(result)

El resultado está vacío.

Está bien en MongoDB:

db.collections.aggregate({"$group":
                        {"_id":{"device_id":"$device_id"},
                        "pubtime":{"$last": "$pubtime"} ,
                       "value":{"$last": "$value"} ,
                        }});
2
养由基 15 nov. 2017 a las 08:27

2 respuestas

La mejor respuesta

No está comprobando los errores, ese es su principal problema. Pipe.All() devuelve un error que usted descarta con elegancia. No hagas eso.

var result = []bson.M{}
err := pipe.All(&result)
fmt.Println(result, err)

Esto imprimirá:

[] a group's fields must be specified in an object

El error lo dice todo. El valor de $group debe ser p. Ej. un valor de bson.M, y no una porción de bson.M:

o3 := bson.M{"$group": bson.M{
    "_id":     bson.M{"device_id": "$device_id"},
    "pubtime": bson.M{"$last": "$pubtime"},
}}
pipe := c.Pipe([]bson.M{o3})
var result = []bson.M{}
err := pipe.All(&result)
fmt.Println(result, err)

Ahora la salida será:

[map[_id:map[device_id:12222] pubtime:2017-11-07 10:41:49.452 +0100 CET] map[_id:map[device_id:1111] pubtime:2017-11-07 10:40:11.204 +0100 CET] map[_id:map[device_id:1232213] pubtime:2017-11-07 10:42:13.658 +0100 CET]] <nil>

Entonces funciona.

Y para ordenar los resultados por pubtime, use $sort. Aquí está el código final:

pipe := c.Pipe([]bson.M{
    {
        "$group": bson.M{
            "_id":     bson.M{"device_id": "$device_id"},
            "pubtime": bson.M{"$last": "$pubtime"},
        },
    },
    {"$sort": bson.M{"pubtime": 1}},
})
var result = []bson.M{}
err := pipe.All(&result)
fmt.Println(result, err)

Si desea que los resultados estén ordenados en orden descendente, utilice:

{"$sort": bson.M{"pubtime": -1}}

También tenga en cuenta que al agrupar, si el grupo _id es un solo campo, no es necesario que lo envuelva en un objeto, simplemente puede usar $device_id como la identificación del grupo:

"$group": bson.M{
    "_id":     "$device_id",
    "pubtime": bson.M{"$last": "$pubtime"},
},
1
icza 15 nov. 2017 a las 08:50

Se puede hacer usando $ group y $ primero en la canalización de agregación de mongodb

Consulta de shell mongodb

db.collection.aggregate([
    {$group: {_id:{device_id:"$device_id"}, pubtime:{$first:"$pubtime"}}}
]);

El resultado que obtenemos después de ejecutar la consulta anterior en mongo shell

{ "_id" : { "device_id" : "12222" }, "pubtime" : ISODate("2017-11-07T09:41:49.452Z") }
{ "_id" : { "device_id" : "1111" }, "pubtime" : ISODate("2017-11-07T09:40:11.204Z") }
{ "_id" : { "device_id" : "1232213" }, "pubtime" : ISODate("2017-11-07T09:37:37.006Z") }
0
Clement Amarnath 15 nov. 2017 a las 07:38