Home  >  Article  >  Backend Development  >  Subtractive Aggregation Mongo Documentation Golang

Subtractive Aggregation Mongo Documentation Golang

WBOY
WBOYforward
2024-02-08 21:05:361116browse

减法聚合 Mongo 文档 Golang

php editor Zimo will introduce to you the subtractive aggregation Mongo document Golang today. In Golang development, using MongoDB as the database is a very common choice. MongoDB provides a powerful aggregation framework that can perform various complex aggregation operations on documents. Among them, subtractive aggregation is a special aggregation operation that can be used to calculate the difference of a certain field in the document. This article will introduce in detail how to use subtractive aggregation to process Mongo documents in Golang, helping developers better understand and apply this function.

Question content

I have this document in mongo

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

I want to use this golang code to decrement "test_value" by one

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,
        })
    }

I'm getting this error

"Cannot aggregate document to mongo. Unable to marshal primitive type to bson document: writerarray can only write to array when on element or value but at top level"

What did i do wrong?


Correct answer


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

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

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

ps 1

To make it easier for others to investigate the issue, please provide a minimal executable reproducible in the future, for example:

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 data collection:

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

(Executed in mongodb shell)

Use packagego.mongodb.org/8ddef92dce6c3f37ab15adc625811345[Email protected protect]5db79b134e9f6b82c0b36e0489ee08ed and mongo:5.0.8, the error I get is:

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

ps 2:

If you don't know, you can directly create the bsond variable like this:

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 (an extra ) at the end of the short declaration of jsoninput). After correcting this I don't think it will cause the error you show in your question. I believe the error is for another jsoninput value.

The above is the detailed content of Subtractive Aggregation Mongo Documentation Golang. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete