I'm trying to make a query in golang language (below I've attached working code of pure mongodb query) using go.mongodb.org/mongo-driver/mongo
library, below is golang query code. I can't get matchStage
to work correctly, I've tried many variants and I'm sure I'm just very inattentive or just don't understand
How can I use $match
, $expr
, $and
and $lte
at once to make a correct matchStage
?
func (r *Mongo) ChatHistory(ctx context.Context, chatID string, f *Filter) ([]*Message, error) {
matchStage := bson.D{
primitive.E{
Key: "$match",
Value: bson.D{
primitive.E{Key: "$expr", Value: bson.D{
primitive.E{Key: "$and", Value: bson.A{
bson.D{
primitive.E{Key: "$lte", Value: bson.D{
primitive.E{
Key: "$create_date",
Value: f.Date, // int64
},
}},
},
}},
}},
},
},
}
sortStage := bson.D{
{
Key: "$sort", Value: bson.D{
primitive.E{Key: "create_date", Value: -1},
},
},
}
limitStage := bson.D{primitive.E{Key: "$limit", Value: f.Count}}
cursor, err := r.colMessage.Aggregate(ctx, mongo.Pipeline{matchStage, sortStage, limitStage})
if err != nil {
l.Error().Err(err).Msg("failed find")
return nil, err
}
var res []*Message
if err = cursor.All(ctx, &res); err != nil {
l.Error().Err(err).Msg("failed find all documents")
return nil, err
}
if err = cursor.Close(ctx); err != nil {
l.Error().Err(err).Msg("failed close cursor")
return nil, err
}
return res, nil
}
Error: (InvalidPipelineOperator) Unrecognized expression '$create_date'
CodePudding user response:
Value of $lte
must be an array not a document:
matchStage := bson.D{
primitive.E{
Key: "$match",
Value: bson.D{
primitive.E{Key: "$expr", Value: bson.D{
primitive.E{Key: "$and", Value: bson.A{
bson.D{
primitive.E{Key: "$lte", Value: bson.A{
"$create_date",
f.Date, // int64
}},
},
}},
}},
},
},
}
Also note that you can leave out the primitive.E
type from the composite literal:
matchStage := bson.D{
{
Key: "$match",
Value: bson.D{
{Key: "$expr", Value: bson.D{
{Key: "$and", Value: bson.A{
bson.D{
{Key: "$lte", Value: bson.A{
"$create_date",
f.Date, // int64
}},
},
}},
}},
},
},
}
But note that your expression is on the mongo playground is incorrect. Quoting from the doc:
$match
takes a document that specifies the query conditions. The query syntax is identical to the read operation query syntax ...
When using $expr
, you have to use $eq
, for example:
matchStage := bson.D{
{
Key: "$match",
Value: bson.D{
{Key: "$expr", Value: bson.D{
{Key: "$and", Value: bson.A{
bson.D{
{Key: "$eq", Value: bson.A{
"$chat_id",
chatID,
}},
},
bson.D{
{Key: "$lte", Value: bson.A{
"$create_date",
f.Date, // int64
}},
},
}},
}},
},
},
}
Try it here: https://mongoplayground.net/p/SBEJD-Fyhjl
You should use a normal query document in $match
.
See this equivalent, much simpler solution:
matchStage := bson.D{
{
Key: "$match",
Value: bson.D{
{Key: "chat_id", Value: chatID},
{Key: "create_date", Value: bson.D{
{
Key: "$lte",
Value: f.Date, // int64
}},
},
},
},
}
And even much-much simpler if you use bson.M
instead of bson.D
:
matchStage := bson.M{
"$match": bson.M{
"chat_id": chatID,
"create_date": bson.M{"$lte": f.Date},
},
}
Of course in this last case you can't use mongo.Pipeline
for the pipeline, but []any
or []bson.M
would also do.