减法聚合Mongo文档Golang

huangapple go评论85阅读模式
英文:

Subtraction Aggregate Mongo Document Golang

问题

我已经将您提供的内容翻译成中文,如下所示:

我在Mongo中有这个文档:

{
  "_id": {
    "$oid": "649d3d688a1f30bf82e77342"
  },
  "test_value": {
    "$numberLong": "10"
  }
}

我想用以下的Golang代码将"test_value"减去一:

jsonInput := []map[string]interface{}{
	{
		"$match": map[string]interface{}{
			"test_value": 10,
		},
	},
	{
		"$set": map[string]interface{}{
			"test_value": map[string]interface{}{
				"$subtract": []interface{}{"test_value", 1}},
		},
	},
})


value, bsonByte, errMarshal := bson.MarshalValue(jsonInput)
if errMarshal != nil {
	modules.DoLog("ERROR", "", "MongoService", "aggregateDocument", "无法将jsonInput转换为BSONByte", true, errMarshal)
	ctx.IndentedJSON(200, gin.H{
		"error": errMarshal.Error(),
	})
	return
}
fmt.Println(value)

bsonD := bson.A{}

errUnmarshal1 := bson.UnmarshalValue(value, bsonByte, &bsonD)
if errUnmarshal1 != nil {
	modules.DoLog("ERROR", "", "MongoService", "aggregateDocument", "无法将BSONByte转换为BSOND", true, errUnmarshal1)
	ctx.IndentedJSON(200, gin.H{
		"error": errUnmarshal1.Error(),
	})
	return
}

_, err := Client.Database("rhanov_queries").Collection(collectionName).Aggregate(ContextMongo, bsonD)
if err != nil {
	modules.DoLog("ERROR", "", "MongoService", "aggregateDocument", "无法将文档聚合到Mongo", true, err)
	ctx.IndentedJSON(200, gin.H{
		"error": err,
	})
}

然后我得到了这个错误:

"无法将文档聚合到Mongo。无法将类型primitive.A编组为BSON文档:WriteArray只能在元素或值上定位时写入数组,但当前定位在顶层"

我做错了什么?

英文:

i have this document in mongo

{
  "_id": {
    "$oid": "649d3d688a1f30bf82e77342"
  },
  "test_value": {
    "$numberLong": "10"
  }
}

i want to subtract "test_value" by one with this golang code

    jsonInput := []map[string]interface{}{
		{
			"$match": map[string]interface{}{
				"test_value": 10,
			},
		},
		{
			"$set": map[string]interface{}{
				"test_value": map[string]interface{}{
					"$subtract": []interface{}{"test_value", 1}},
			},
		},
	})


    value, bsonByte, errMarshal := bson.MarshalValue(jsonInput)
	if errMarshal != nil {
		modules.DoLog("ERROR", "", "MongoService", "aggregateDocument", "cannot Marshal jsonInput to BSONByte", true, errMarshal)
		ctx.IndentedJSON(200, gin.H{
			"error": errMarshal.Error(),
		})
		return
	}
	fmt.Println(value)
	
	bsonD := bson.A{}

	errUnmarshal1 := bson.UnmarshalValue(value, bsonByte, &bsonD)
	if errUnmarshal1 != nil {
		modules.DoLog("ERROR", "", "MongoService", "aggregateDocument", "cannot Unmarshal BSONByte to BSOND", true, errUnmarshal1)
		ctx.IndentedJSON(200, gin.H{
			"error": errUnmarshal1.Error(),
		})
		return
	}
	
	_, err := Client.Database("rhanov_queries").Collection(collectionName).Aggregate(ContextMongo, bsonD)
	if err != nil {
		modules.DoLog("ERROR", "", "MongoService", "aggregateDocument", "cannot aggregate document to Mongo", true, err)
		ctx.IndentedJSON(200, gin.H{
			"error": err,
		})
	}

and i get this error

"cannot aggregate document to Mongo. cannot marshal type primitive.A to a BSON Document: WriteArray can only write a Array while positioned on a Element or Value but is positioned on a TopLevel"

what did i do wrong?

答案1

得分: 1

"$subtract": []interface{}{"test_value", 1}

请注意,这里的"test_value"是一个字面量。该表达式的意思是从字符串test_value中减去数字1,这是无效的,也不是你想要的。你想要引用字段路径。所以你应该在它前面加上$(参见聚合表达式)。以下是修正后的代码:

"$subtract": []interface{}{"$test_value", 1}

PS 1:

为了方便其他人查看问题,请在以后提供一个最小可执行的重现示例,例如:

package main

import (
	"context"
	"fmt"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	jsonInput := []map[string]interface{}{
		{
			"$match": map[string]interface{}{
				"test_value": 10,
			},
		},
		{
			"$set": map[string]interface{}{
				"test_value": map[string]interface{}{
					"$subtract": []interface{}{"test_value", 1},
					// `test_value` should be prefixed with $ like this:
					// "$subtract": []interface{}{"$test_value", 1},
				},
			},
		},
	}

	typ, buf, err := bson.MarshalValue(jsonInput)
	if err != nil {
		panic(err)
	}
	fmt.Println(typ)

	var bsonD bson.A

	if err := bson.UnmarshalValue(typ, buf, &bsonD); err != nil {
		panic(err)
	}

	client, err := mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://localhost"))
	if err != nil {
		panic(err)
	}
	collection := client.Database("demo").Collection("values")
	cur, err := collection.Aggregate(context.Background(), bsonD)
	if err != nil {
		panic(err)
	}
	defer cur.Close(context.Background())
	for cur.Next(context.Background()) {
		fmt.Printf("%+v", cur.Current)
	}
}

并使用以下方式初始化集合数据:

db.values.insert({ _id: ObjectId('649d3d688a1f30bf82e77342'), test_value: 10 })

(在MongoDB Shell中执行)

使用go.mongodb.org/mongo-driver@v1.12.0mongo:5.0.8包,我得到的错误是:

panic: (TypeMismatch) Failed to optimize pipeline :: caused by :: can't $subtract int from string

PS 2:

如果你不知道,你可以直接这样创建bsonD变量:

bsonD := bson.A{
	bson.M{
		"$match": bson.M{
			"test_value": 10,
		},
	},
	bson.M{
		"$set": bson.M{
			"test_value": bson.M{
				"$subtract": bson.A{"$test_value", 1},
			},
		},
	},
}

PS 3:

你展示的代码有一个语法错误(jsonInput的短声明结尾有一个多余的))。纠正这个错误后,我不认为它会导致你在问题中展示的错误。我相信错误是由另一个jsonInput值引起的。

英文:
"$subtract": []interface{}{"test_value", 1}

Please note that here "test_value" is a literal. The expression means subtract the number 1 from the string test_value, which is invalid and is not what you want. You want to refer to the field path instead. So you should prefix it with $ (see aggregation expressions). Here is the corrected code:

"$subtract": []interface{}{"$test_value", 1}

PS 1:

To make it easy for others to look into the issue, please provide a minimal executable reproducer in the future, such as:

package main

import (
	"context"
	"fmt"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	jsonInput := []map[string]interface{}{
		{
			"$match": map[string]interface{}{
				"test_value": 10,
			},
		},
		{
			"$set": map[string]interface{}{
				"test_value": map[string]interface{}{
					"$subtract": []interface{}{"test_value", 1},
					// `test_value` should be prefixed with $ like this:
					// "$subtract": []interface{}{"$test_value", 1},
				},
			},
		},
	}

	typ, buf, err := bson.MarshalValue(jsonInput)
	if err != nil {
		panic(err)
	}
	fmt.Println(typ)

	var bsonD bson.A

	if err := bson.UnmarshalValue(typ, buf, &bsonD); err != nil {
		panic(err)
	}

	client, err := mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://localhost"))
	if err != nil {
		panic(err)
	}
	collection := client.Database("demo").Collection("values")
	cur, err := collection.Aggregate(context.Background(), bsonD)
	if err != nil {
		panic(err)
	}
	defer cur.Close(context.Background())
	for cur.Next(context.Background()) {
		fmt.Printf("%+v", cur.Current)
	}
}

And initialize the collection data with:

db.values.insert({ _id: ObjectId('649d3d688a1f30bf82e77342'), test_value: 10 })

(executed in MongoDB Shell)

With the package go.mongodb.org/mongo-driver@v1.12.0 and mongo:5.0.8, the error I got is:

panic: (TypeMismatch) Failed to optimize pipeline :: caused by :: can't $subtract int from string

PS 2:

In case you don't know, you can create the bsonD variable like this directly:

bsonD := bson.A{
	bson.M{
		"$match": bson.M{
			"test_value": 10,
		},
	},
	bson.M{
		"$set": bson.M{
			"test_value": bson.M{
				"$subtract": bson.A{"$test_value", 1},
			},
		},
	},
}

PS 3:

The code you show has a syntax error (the end of the short declaration of jsonInput has an extra )). After correcting this error, I don't think it can cause the error you show in your question. I believe the error is for another jsonInput value.

huangapple
  • 本文由 发表于 2023年6月29日 17:50:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76579937.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定