2

While working on Golang Mongo Driver, I am stuck with this weird beahviour to use inline

Seems like bson:",inline" doesnt work with Embedded Structs.

Not able to understand why such a behaviour?

inline Inline the field, which must be a struct or a map, causing all of its fields or keys to be processed as if they were part of the outer struct. For maps, keys must not conflict with the bson keys of other struct fields.

import (
    "context"
    "encoding/json"
    "fmt"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

//Expected Output
//{
//  "ID": "5e6e96cb3cfd3c0447d3e368",
//  "product_id": "5996",
//  "Others": {
//      "some": "value"
//  }
//}

//Actual Output
//{
//  "ID": "5e6e96cb3cfd3c0447d3e368",
//  "product_id": "5996"
//}

type Product struct {
    ID        primitive.ObjectID `bson:"_id"`
    ProductId string             `bson:"product_id" json:"product_id"`
    *SchemalessDocument
}

type SchemalessDocument struct {
    Others    bson.M             `bson:",inline"`
}


func main() {

    clientOptions := options.ClientOptions{
        Hosts: []string{"localhost"},
    }
    client, _ = mongo.NewClient(&clientOptions)
    client.Connect(context.TODO())
    var p Product
    collection := client.Database("Database").Collection("collection")
    query := bson.D{{"product_id", "5996"}}
    _ = collection.FindOne(context.TODO(), query).Decode(&p)

    jsonResp, _ := json.Marshal(p)
    fmt.Println(string(jsonResp))

}

But the same code works if I change

type Product struct {
    ID        primitive.ObjectID `bson:"_id"`
    ProductId string             `bson:"product_id" json:"product_id"`
    Others    bson.M             `bson:",inline"`
}
Art
  • 414
  • 7
  • 24
  • Try with type Product struct { ID primitive.ObjectID `bson:"_id"` ProductId string `bson:"product_id" json:"product_id"` Document *Schemaless `bson:"others"` } – nguyenhoai890 Apr 10 '20 at 03:40
  • @nguyenhoai890 Its not working . Have you tried it? Is it working for you? I am still getting `{"ID":"5e6e96cb3cfd3c0447d3e368","product_id":"5996","Document":null}` or `{"ID":"5e6e96cb3cfd3c0447d3e368","product_id":"5996","Document":{"Others":null}}` – Art Apr 10 '20 at 05:29
  • Can you post your example data in DB? – nguyenhoai890 Apr 10 '20 at 05:48
  • @nguyenhoai890 It is unstructured document like `{ "_id":"", "product_id":"", "some":"value", "some_more":"value2" }` , But i want to convert it to Struct for fields which I know and rest to a map using `inline` – Art Apr 10 '20 at 05:56
  • The ``bson:",inline"`` exposes for 1 level. if you put the inline tag in ``SchemalessDocument``, the mongodb driver will expose out for 1 level which is the bson.M so the result still will be m:{....}. That the reason why your second code works, because it exposes 1 level down to map[string]interface{}. – nguyenhoai890 Apr 10 '20 at 09:17
  • about the put all things into one struct, do you have any reason to do that? – nguyenhoai890 Apr 10 '20 at 09:17
  • @nguyenhoai890 I dnt have schema of document, so I want to construct partial schema and rest would be as `bson.M`. But problem is `bson:inline` doesnt work for Embedded Structs, so I have to add this with every struct as stated in second part of code. I wanted to add it once in Base class only – Art Apr 10 '20 at 09:54
  • @nguyenhoai890 Also, can you demonstrate in the code what do you mean by `inline tag in SchemalessDocument ` . I tried but still i dont get any values in `SchemalessDocument` `Others` is `nil` – Art Apr 10 '20 at 09:56
  • With inline tag in SchemalessDocument, it only works when json in DB like: { "ID": "5e6e96cb3cfd3c0447d3e368", "product_id": "5996", "Others": { // you should point the name "Others" in your SchemalessDocument "some": "value" } } it will expose list off fields in the Others into SchemalessDocument – nguyenhoai890 Apr 10 '20 at 11:01
  • The only way, I can think, is you can use type Product struct { ID primitive.ObjectID `bson:"_id"` ProductId string `bson:"product_id" json:"product_id"` Others map[string] interface{} `bson:",inline"` } – nguyenhoai890 Apr 10 '20 at 11:03
  • @nguyenhoai890 Thats correct. My question was this only, why `inline` is not working when it is inside `Embedded Struct`. Thanks for the response. – Art Apr 10 '20 at 12:28

1 Answers1

5

This is what it should be

type Product struct {
    ID        primitive.ObjectID `bson:"_id"`
    ProductId string             `bson:"product_id" json:"product_id"`
    *SchemalessDocument          `bson:",inline"`
}

type SchemalessDocument struct {
    Others    bson.M             `bson:"others"`
}

kitta
  • 1,723
  • 3
  • 23
  • 33