mongodbgomongo-go

How can I define a type wrapper for primitive's ObjectID?


I am using MongoDB to develop a ticketing system using Go. I have two entities: users and tickets, each having their own unique ID. I would like to be able to differentiate between the two types of IDs so that functions can request to receive either a UserID or a TicketID specifically.

I have tried to define two new types, whose base type is primitive.ObjectID:

type UserID primitive.ObjectID
type TicketID primitive.ObjectID

I then used this type within my user struct:

type User struct {
  ID UserID `json:"id" bson:"_id"`
}

Finally I tried to retrieve an array of all users in the database using this code:

func (coll *mongo.Collection) GetAllUsers(ctx context.Context) ([]User, error) {
  cursor, err := coll.Find(ctx, bson.D{})
  if err != nil {
    return []User{}, err
  }
  users := []User{}
  err = cursor.All(ctx, &users)
  if err != nil {
    return []User{}, err
  }
  return users, nil
}

However, trying to do this results in the following error: cannot decode ObjectID into an array

How can I achieve differentiation between UserIDs and TicketIDs while avoiding this error?


Solution

  • A type definition creates a new, distinct type and strips its methods:

    type UserID primitive.ObjectID
    
    type TicketID primitive.ObjectID
    

    After these, the mongo and bson packages will no longer recognize UserID and TicketID as ObjectID (just as their underlying byte array), and will not know how to unmarshal MongoDB ObjectID into them.

    Instead use type aliases, then you will have distinct names in your code, and since a type alias does not create a new type (just binds another identifier to the same type), it will work as you expect it:

    type UserID = primitive.ObjectID
    
    type TicketID = primitive.ObjectID
    

    Note that after the above type declarations, UserID, TicketID and primitive.ObjectID will be the same, identical type, so you shouldn't expect to be able to differentiate them by type.