简体   繁体   中英

Get _id from mongoDB using gqlgen

I'm using Go and gqlgen to access my mongoDB database and was wondering how do I access the id field from the database? This is what I have currently and _id returns an empty string

type Post {
  _id: ID!
  title: String!
  content: String!
  comments: [Comment!]
  author: User!
  created: Date!
}

type Query {
  post(_id: ID!): Post
  ...
}
func (r *queryResolver) Post(ctx context.Context, id string) (*model.Post, error) {
    var post model.Post

    _id, err := primitive.ObjectIDFromHex(id)
    if err != nil {
        return nil, err
    }

    err = db.Posts.FindOne(context.TODO(), bson.D{{Key: "_id", Value: _id}}).Decode(&post)

    if err != nil {
        return nil, err
    }

    return &post, nil
}

The ID type in gqlgen creates a string, but _id in mongo is probably a primitive.ObjectId which can create issues depending on how you interact with mongo.

Better to set a bson tag as _id

consider setting the following struct to overwrite the gql generated flow. You can convert the id into a string using the Hex() method.

type Post struct{
  ID primitive.ObjectID `bson:"_id" json:"id"`
  title: string
  content: string
  comments: []Comment
  author: User
  created: time.Time
}

You might want to do this automatically if you have many structs with _ids. To avoid having to overwrite, you can implement a hook to autogenerate the bson tags for you

 type Post {
  id: ID!
  title: String!
  content: String!
  comments: [Comment!]
  author: User!
  created: Date!
}

now a new directory in your file structure called "hooks" and create a new file "bson.go"

copy and paste the following

package main

import (
    "fmt"
    "os"

    "github.com/99designs/gqlgen/api"
    "github.com/99designs/gqlgen/codegen/config"
    "github.com/99designs/gqlgen/plugin/modelgen"
)

func mutateHook(b *modelgen.ModelBuild) *modelgen.ModelBuild {
    for _, model := range b.Models {
        for _, field := range model.Fields {
            name := field.Name
            if name == "id" {
                name = "_id"
            }
            field.Tag += ` bson:"` + name + `"`
        }
    }
    return b
}

func main() {
    cfg, err := config.LoadConfigFromDefaultLocations()
    if err != nil {
        fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
        os.Exit(2)
    }

    p := modelgen.Plugin{
        MutateHook: mutateHook,
    }

    err = api.Generate(cfg,
        api.NoPlugins(),
        api.AddPlugin(&p),
    )
    if err != nil {
        fmt.Fprintln(os.Stderr, err.Error())
        os.Exit(3)
    }
}

now in your main.go add this to the top

//go:generate go run hooks/bson.go

now when you run go generate not only will gqlgen do it's normal generation, but it will also add bson tags to all of our models. As well as any field with the name id to have a bson tag of _id

source: https://github.com/99designs/gqlgen/issues/865

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM