4

I'm having some issues creating unique indexes for some of my data using the official MongoDB driver for Go.

So I have a struct like this:

type Product struct {
    ID        primitive.ObjectID `json:"_id" bson:"_id"`
    Name      string             `json:"name" bson:"name"`
    Price     float64            `json:"price" bson:"price"`
    Attribute []Attribute        `json:"attribute" bson:"attribute"`
    Category  string             `json:"category" bson:"category"`
}

And then I wan to create a unique index for the name property. I tried to do something like this in my Createfunction (for products)

func Create(c echo.Context) error {

    //unique index here 
    indexModel, err := productCollection.Indexes().CreateOne(context.Background(),
        IndexModel{
            Keys:    bsonx.Doc{{"name", bsonx.Int32(1)}},
            Options: options.Index().SetUnique(true),
        })
    if err != nil {
        log.Fatalf("something went wrong: %+v", err)
    }

    //create the product here
    p := new(Product)
    if err := c.Bind(p); err != nil {
        log.Fatalf("Could not bind request to struct: %+v", err)
        return util.SendError(c, "500", "something went wrong", "failed")
    }
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    result, _ := productCollection.InsertOne(ctx, p)

    return util.SendSuccess(c, result.InsertedID)

}

The problem is I don't exactly know how to pass indexModel as an option in the context before creating the product. Also, I'm not sure that with what I'm doing, I'm creating the index just once (which is what I want to do). I'd appreciate it if I could be pointed in the right direction on how to do this.

I'm using the echo framework for Go, just in case this provides more context.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
imadu
  • 69
  • 2
  • 6
  • That is the official MongoDB driver, but there is no default. For there to be a default, there would have to be some driver that would be used when you make no selection. That is obviously not the case. – Jonathan Hall Feb 29 '20 at 21:34
  • Oh I see what you mean. Thanks for pointing that out :) – imadu Feb 29 '20 at 21:36

2 Answers2

4

Your code will attempt to create the index every time the Create function is called, which will work, but is not very efficient, as an index only needs to be created once (or if it doesn't exist). I would recommend letting creation of your index be the responsibility of the function that sets up the connection to the DB, or a function run right after initialising the DB connection, such that it is run only once (when your program starts).

As the collection.Indexes().CreateOne(...) method doesn't return an error upon trying to create an index that already exists, you can use this as a way to ensure the index exists, similar to how the unofficial MongoDB driver had an EnsureIndex function.

Alternatively, you could do what Cahaba Data suggests in his answer, which is to make index creation be a one-time DB admin task instead of a responsibilty of your application. I've previously had discussions with some colleagues on this, and while I do agree that it technically is a one-time DB admin task, I still prefer to have my application ensure at startup that the indexes it needs are in fact there, creating them if they are not. After all, my application could malfunction / be crippled if someone forgets to or creates wrong indices. It also provides good documentation on which indices your application needs / uses, instead of having to communicate this with the DB admin and hoping that he / she / it will take proper note of it. Feel free to form your own opinion of course :)

Bart van Oort
  • 330
  • 2
  • 7
  • MongoDB or the Go driver doesn’t actually raise an error if you create the same index multiple times. It is safe to create the indexes you need at app startup. – Stefan Arentz Mar 01 '20 at 04:26
  • Okay, but it would be better to create the index when I initialize my DB, and then call the create function normally, and that should solve the problem. Right? – imadu Mar 01 '20 at 13:29
  • @StefanArentz Hmmm, you are right, I just tried it, the Go driver does indeed not return an error upon creating an index that already exists. I'll edit my answer – Bart van Oort Mar 01 '20 at 13:34
  • @IkechukwuMadu Yes indeed, if by 'normally' you mean without the index creation part. – Bart van Oort Mar 01 '20 at 13:37
  • 1
    Indexes defined in code also mean they're created in local dev environments on new machines for new hires as well as in any test environments spun up ad-hoc. In-code is definitely the way to go. – fIwJlxSzApHEZIl Apr 25 '22 at 18:52
0

yes I kind of look at this in that creating an index is a 1-time DBA/Admin event. It's not an app/code task. log into mongo with appropriate permission, create index, log out....that's it. no code other then the mongo shell command to createIndex.

Cahaba Data
  • 624
  • 1
  • 4
  • 4