title: mongodb-go-driver/bson struct to bson.Document encoding
body: <p>I'm working with <a href="https://github.com/mongodb/mongo-go-driver" rel="noreferrer">https://github.com/mongodb/mongo-go-driver</a> and
  currently trying to implement a partial update of such struct</p>
  
  <pre><code>type NoteUpdate struct {
      ID        string `json:"id,omitempty" bson:"_id,omitempty"`
      Title     string `json:"title" bson:"title,omitempty"`
      Content   string `json:"content" bson:"content,omitempty"`
      ChangedAt int64  `json:"changed_at" bson:"changed_at"`
  }
  </code></pre>
  
  <p>For instance, if I have</p>
  
  <pre><code>noteUpdate := NoteUpdate{ Title: "New Title" }
  </code></pre>
  
  <p>Then I expect that the only "title" field in the stored document will be changed.</p>
  
  <p>I need to write something like</p>
  
  <pre><code>collection.FindOneAndUpdate(context.Background(),
      bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
      // I need to encode non-empty fields here
      bson.NewDocument(bson.EC.SubDocument("$set", bson.NewDocument(...)))
  )
  </code></pre>
  
  <p>The problem is that I don't want to manually encode each non-empty field with <code>bson.EC.String(...)</code> or <code>bson.EC.Int64(...)</code>. I tried to use <code>bson.EC.InterfaceErr(...)</code> but got an error </p>
  
  <blockquote>
    <p>Cannot create element for type *models.NoteUpdate, try using bsoncodec.ConstructElementErr</p>
  </blockquote>
  
  <p>Unfortunately, there is no such function in bsoncodec. The only way I found is to create wrapper </p>
  
  <pre><code>type SetWrapper struct {
      Set interface{} `bson:"$set,omitempty"`
  }
  </code></pre>
  
  <p>And use it like</p>
  
  <pre><code>partialUpdate := &amp;NoteUpdate{
      ID: "some-note-id", 
      Title: "Some new title",
   }
  updateParam := SetWrapper{Set: partialUpdate}
  collection.FindOneAndUpdate(
      context.Background(),
      bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
      updateParam,
  )
  </code></pre>
  
  <p>It works, but is it possible to achieve the same with bson/bsoncodec document builders ?</p>
  
  <p>UPD. The full context of my question:
  I wrote the REST endpoint for <strong>partially</strong> updating "Note" documents(stored in MongoDB). Code that I have now:</p>
  
  <pre><code>var noteUpdate models.NoteUpdate
  ctx.BindJSON(&amp;noteUpdate)    
  //omit validation and errors handling
  updateParams := services.SetWrapper{Set: noteUpdate}
  res := collection.FindOneAndUpdate(
  context.Background(),
  bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
      updateParams,
      findopt.OptReturnDocument(option.After),
  )
  </code></pre>
  
  <p>Code that I want to have</p>
  
  <pre><code>var noteUpdate models.NoteUpdate
  ctx.BindJSON(&amp;noteUpdate)    
  //omit validation and errors handling
  res := collection.FindOneAndUpdate(
      context.Background(),
      bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
      bson.NewDocument(
          //bsoncodec.ConstructElement doesn't exists
          bsoncodec.ConstructElement("$set", &amp;noteUpdate)),
          ),
      findopt.OptReturnDocument(option.After),
  )
  </code></pre>
  
  <p>Code that I <strong>don't</strong> want to have</p>
  
  <pre><code>var noteUpdate models.NoteUpdate
  ctx.BindJSON(&amp;noteUpdate)
  //omit validation and errors handling
  bsonNote := bson.NewDocument()
  if noteUpdate.Title != "" {
      bsonNote.Append(bson.EC.String("title", noteUpdate.Title))
  }
  if noteUpdate.Content != "" {
      bsonNote.Append(bson.EC.String("content", noteUpdate.Content))
  }
  //..setting the rest of the fields...
  res := collection.FindOneAndUpdate(
      context.Background(),
      bson.NewDocument(bson.EC.String("_id", noteUpdate.ID)),
      bson.NewDocument(bson.EC.SubDocument("$set", bsonNote)),
      findopt.OptReturnDocument(option.After),
  )
  </code></pre>
  
  <p>So, the precise question is - is there any way to build *bson.Document dynamically based on <code>bson</code> tags(without predefined wrappers like my SetWrapper)? </p>