英文:
incorrectly drafted MongoDB aggregation pipeline $match stage
问题
我正在尝试使用go.mongodb.org/mongo-driver/mongo
库在golang语言中进行查询(下面我附上了纯mongodb查询的工作代码),以下是golang查询代码。我无法正确使用matchStage
,我尝试了许多变体,我确定我只是非常粗心或者根本不理解。
如何同时使用$match
、$expr
、$and
和$lte
来创建一个正确的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
}
错误:(InvalidPipelineOperator) Unrecognized expression '$create_date'
英文:
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'
答案1
得分: 2
$lte
的值必须是一个数组而不是一个文档:
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
}},
},
}},
}},
},
},
}
另外请注意,你可以从复合字面量中省略primitive.E
类型:
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
}},
},
}},
}},
},
},
}
但请注意,你在Mongo Playground上的表达式是不正确的。引用自文档:
在使用$expr
时,你必须使用$eq
,例如:
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
}},
},
}},
}},
},
},
}
在这里尝试:https://mongoplayground.net/p/SBEJD-Fyhjl
你应该在$match
中使用一个普通的查询文档。
看看这个等效的、更简单的解决方案:
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
}},
},
},
},
}
如果你使用bson.M
而不是bson.D
,甚至更简单:
matchStage := bson.M{
"$match": bson.M{
"chat_id": chatID,
"create_date": bson.M{"$lte": f.Date},
},
}
当然,在这种情况下,你不能使用mongo.Pipeline
作为管道,但[]any
或[]bson.M
也可以。
英文:
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 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论