code: func (t *Transaction) Save(c *Collection, model Model) {
  	if c == nil {
  		t.setError(newNilCollectionError("Save"))
  		return
  	}
  	if err := c.checkModelType(model); err != nil {
  		t.setError(fmt.Errorf("zoom: Error in Save or Transaction.Save: %s", err.Error()))
  		return
  	}
  	// Create a modelRef and start a transaction
  	mr := &modelRef{
  		collection: c,
  		model:      model,
  		spec:       c.spec,
  	}
  	// Save indexes
  	// This must happen first, because it relies on reading the old field values
  	// from the hash for string indexes (if any)
  	t.saveFieldIndexes(mr)
  	// Save the model fields in a hash in the database
  	hashArgs, err := mr.mainHashArgs()
  	if err != nil {
  		t.setError(err)
  	}
  	if len(hashArgs) > 1 {
  		// Only save the main hash if there are any fields
  		// The first element in hashArgs is the model key,
  		// so there are fields if the length is greater than
  		// 1.
  		t.Command("HMSET", hashArgs, nil)
  	}
  	// Add the model id to the set of all models for this collection
  	if c.index {
  		t.Command("SADD", redis.Args{c.IndexKey(), model.ModelID()}, nil)
  	}
  }
docs: // Save writes a model (a struct which satisfies the Model interface) to the
  // redis database inside an existing transaction. save will set the err property
  // of the transaction if the type of model does not match the registered
  // Collection, which will cause exec to fail immediately and return the error.
  // To make a struct satisfy the Model interface, you can embed zoom.RandomID,
  // which will generate pseudo-random ids for each model. Any errors encountered
  // will be added to the transaction and returned as an error when the
  // transaction is executed.