Reputation: 608
I'm trying to get an array of documents using aggregation. Aggregation to simultaneously match an array of chats, sort by timestamp, and then group by chat_id, selecting only the last message from each. So I have an array of three chat_id and I want to get the last three messages that have that chat_id.
Below are two examples: The first is the aggregation in the console and an example of the response I get. The second is a variant in golang, but I get empty objects in the output
This is MongoDB playgroud work example
First example
db.message.aggregate([
{
$match: {
chat_id: {
$in: ["dtlzoD9fI15q8_YM6eqp", "unps_ZwBZ7mCubC3TsKl"],
},
}
},
{
$sort: {
"created": -1,
},
},
{
$group: {
"_id": {"chat_id": "$chat_id"},
"doc": { "$last": "$$ROOT" }
}
}
])
First response
[
{
"_id": {
"chat_id": "unps_ZwBZ7mCubC3TsKl"
},
"doc": {
"_id": {"$oid": "63ac61d71a11d3b05340c001"},
"id": "wsBFKoN51q5v4Nnv3A-B",
"chat_id": "unps_ZwBZ7mCubC3TsKl",
"body": "Certainty determine at of arranging perceived situation or. Or wholly pretty county in oppose. Favour met itself wanted settle put garret twenty. In astonished apartments resolution so an it. Unsatiable on by contrasted to reasonable companions an. On otherwise no admitting to suspicion furniture it. ",
"created": 1672241623466
}
},
{
"_id": {
"chat_id": "dtlzoD9fI15q8_YM6eqp"
},
"doc": {
"_id": {"$oid": "63ac607f141f0526cba7113d"},
"id": "jhjVxQUzQbPCLebnupS9",
"chat_id": "dtlzoD9fI15q8_YM6eqp",
"body": "Certainty determine at of arranging perceived situation or. Or wholly pretty county in oppose. Favour met itself wanted settle put garret twenty. In astonished apartments resolution so an it. Unsatiable on by contrasted to reasonable companions an. On otherwise no admitting to suspicion furniture it. ",
"created": 1672241279354
}
}
]
Second example. This isn't work example
type Message struct {
ID string `json:"id" bson:"id"`
ChatID string `json:"chat_id" bson:"chat_id"`
Body string `json:"body" bson:"body"`
Created int64 `json:"created" bson:"created"`
}
...
ids := []string{"unps_ZwBZ7mCubC3TsKl", "dtlzoD9fI15q8_YM6eqp"}
matchStage := bson.D{{
Key: "$match", Value: bson.D{{Key: "chat_id", Value: bson.D{{Key: "$in", Value: ids}}}},
}}
sortStage := bson.D{{"$sort", bson.D{{"created", -1}}}}
groupStage := bson.D{{
Key: "$group", Value: bson.D{
{
Key: "_id", Value: bson.D{
{"chat_id", "$chat_id"},
},
},
{
Key: "message", Value: bson.D{
{"$last", "$$ROOT"},
},
},
},
}}
cursor, err := db.Aggregate(context.Background(), mongo.Pipeline{matchStage, groupStage, sortStage})
if err != nil {}
var messages []*Message
err = cursor.All(context.Background(), &messages)
if err != nil {
fmt.Print("Cursor err: ", err)
return
}
defer func() {
err := cursor.Close(context.Background())
if err != nil {
return
}
}()
Second Response
MSG: &{ 0} // empty data
MSG: &{ 0}
What I want to get out of aggregation
[
{
"_id": {"$oid": "63ac607f141f0526cba7113d"},
"id": "jhjVxQUzQbPCLebnupS9",
"chat_id": "dtlzoD9fI15q8_YM6eqp",
"body": "Certainty determine at of arranging perceived situation or. Or wholly pretty county in oppose. Favour met itself wanted settle put garret twenty. In astonished apartments resolution so an it. Unsatiable on by contrasted to reasonable companions an. On otherwise no admitting to suspicion furniture it. ",
"created": 1672241279354
},
{
"_id": {"$oid": "63ac61d71a11d3b05340c001"},
"id": "wsBFKoN51q5v4Nnv3A-B",
"chat_id": "unps_ZwBZ7mCubC3TsKl",
"body": "Certainty determine at of arranging perceived situation or. Or wholly pretty county in oppose. Favour met itself wanted settle put garret twenty. In astonished apartments resolution so an it. Unsatiable on by contrasted to reasonable companions an. On otherwise no admitting to suspicion furniture it. ",
"created": 1672241623466
},
]
Upvotes: 2
Views: 160
Reputation: 3002
This issue is probably because your message schema isn't correct (note there is a small difference between your JS aggregate and your go one in that use use doc
in the former and message
in the latter, I'll stick with message
type MessageInner struct {
ID string `json:"id" bson:"id"`
ChatID string `json:"chat_id" bson:"chat_id"`
Body string `json:"body" bson:"body"`
Created int64 `json:"created" bson:"created"`
}
type Message struct {
MessageInner Doc `json:"message" bson:"message"`
}
An alternate would be to use the $replaceRoot
aggregation stage at the end
{ $replaceRoot: { newRoot: "$message" } }
Upvotes: 1