go-mongox icon indicating copy to clipboard operation
go-mongox copied to clipboard

聚合查询时,语法不正确导致无法查询数据?

Open shuqingzai opened this issue 1 month ago • 2 comments

在提交之前请先查找 已有 issues,避免重复上报。| Before submitting, please search for existing issues to avoid duplicate reports.

并且确保自己已经 | Also, ensure that you have:

  • [x] 阅读过文档 | Read the documentation
  • [x] 阅读过注释 | Reviewed the comments
  • [x] 阅读过例子 | Looked at the examples

您使用的 mongox 版本 | The version of mongox you are using

您遇到的问题 | The issue you encountered.

我需要类似以下的查询语法

                 startTime := time.Now()
                endTime := startTime.AddHour()
		pipeline := []bson.M{
			// Match stage
			{
				"$match": bson.M{
					"createdAt": bson.M{
						"$gte": startTime,
						"$lt":  endTime,
					},
				},
			},
			// Group stage
			{
				"$group": bson.M{
					"_id": bson.M{
						"statAt": bson.M{
							"$dateToString": bson.M{
								"format": "%Y-%m-%d %H",
								"date":   "$createdAt",
							},
						},
						"userId":       "$userId",
						"type":         "$type",
					},
					"statCount": bson.M{
						"$sum": 1,
					},
					"statCredits": bson.M{
						"$sum": "$credits",
					},
				},
			},
			// Sort stage
			{
				"$sort": bson.M{
					"_id.statAt": -1,
					"_id.type":   -1,
				},
			},
		}
  1. 我使用 aggregation 相关构造器
	stageBuilder := aggregation.NewStageBuilder()

	// Match stage
	matchBuilder := aggregation.NewBuilder().
		Gte("createdAt", in.StartTime).
		Lt("createdAt", in.EndTime)

	stageBuilder.Match(matchBuilder.Build())

	// Group stage
	groupIDBuilder := aggregation.NewBuilder().
		DateToString("statAt", "$createdAt", &aggregation.DateToStringOptions{
			Format: "%Y-%m-%d %H",
			// Timezone: "UTC",
		}).
		KeyValue("userId", "$userId").
		KeyValue("type", "$type")

	// 添加统计数量的管道阶段
	groupFields := aggregation.NewBuilder().
		Sum("statCount", 1).
		Sum("statCredits", "$credits")

	stageBuilder.Group(groupIDBuilder.Build(), groupFields.Build()...)

	// Sort stage
	stageBuilder.Sort(bson.D{
		{"_id.date", -1},
		{"_id.type", -1},
	})

	// 序列化查询语句
	stageBuilderBytes, _ := json.Marshal(stageBuilder.Build())

	println(string(stageBuilderBytes))
  1. 我得到了以下语句
[{"$match":{"createdAt":{"$gte":["2025-10-17T03:00:00Z"],"$lt":["2025-10-17T04:00:00Z"]}}},{"$group":{"_id":{"statAt":{"$dateToString":{"date":"$createdAt","format":"%Y-%m-%d %H"}},"userId":"$userId","type":"$type"},"statCount":{"$sum":1},"statCredits":{"$sum":"$credits"}}},{"$sort":{"_id.date":-1,"_id.type":-1}}]
  1. 它们的差异在于 $match 阶段的 createdAt 条件类型不一致
Image
  1. 我使用 Mongo SHELL 执行无法查询到数据, 因为 createdAt 语法不对

复现步骤 | Steps to reproduce

请提供简单的复现代码 | Please provide simple code to reproduce the issue.

错误日志或者截图 | Error logs or Screenshots

你排查的结果,或者你觉得可行的修复方案 | Your Findings or Possible Solutions

可选。我们希望你能够尽量先排查问题,帮助我们减轻维护负担。这对于你个人能力提升同样是有帮助的。| Optional. We hope you can try to troubleshoot the issue first, helping us to reduce our maintenance burden. This is also beneficial for your personal skill development

您期望的结果 | Expected Outcome

你设置的的 Go 环境 | Your Go Environment Setting

上传 go env 的结果 | Upload the result of go env

shuqingzai avatar Oct 17 '25 06:10 shuqingzai

@chenmingyong0423 语法错误导致无法按时间聚合数据 下面这样就行 Image

shuqingzai avatar Oct 17 '25 06:10 shuqingzai

理解你的疑问,我来解释一下这个问题吧。首先,先说明一下,通过 aggregation.NewBuilder() 获得的构建器,是用于构建聚合表达式的构建器,我们知道,聚合表达式(Aggregation Expressions) 和普通的 查询 / 更新表达式 在 MongoDB 里既有相似之处,也有显著区别。而你这里的:

bson.M{
	"createdAt": bson.M{
		"$gte": startTime,
		"$lt":  endTime,
	},
}

其实不算 聚合表达式,而是归属于 查询表达式 因此你不能用 aggregation.NewBuilder() 去构建,而是用 queryBuilder := query.NewBuilder().Gte("createdAt", in.StartTime).Lt("createdAt", in.EndTime) 去构建才是对的,所以将 queryBuilder := query.NewBuilder().Gte("createdAt", in.StartTime).Lt("createdAt", in.EndTime) 代替 matchBuilder := aggregation.NewBuilder().Gte("createdAt", in.StartTime).Lt("createdAt", in.EndTime) 就可以得到正确的数据了。看来我需要在某个地方去强调一下这些构建器的区别,用户才能够容易,正确地使用。感谢你的反馈!

chenmingyong0423 avatar Oct 20 '25 07:10 chenmingyong0423