Структуры Golang bson — используйте несколько имен полей для одного поля в json, но только одно для записи в базу данных

#json #mongodb #go #struct #bson

#json #mongodb #Вперед #структура #bson

Вопрос:

У меня есть такая структура —

 type Address struct {
    AddressLine1 string        `json:"addressLine1" bson:"addressLine1"`
    AddressLine2 string        `json:"addressLine2" bson:"addressLine2"`
    Landmark     string        `json:"landmark" bson:"landmark"`
    Zipcode      string        `json:"zipcode" bson:"zipcode"`
    City         string        `json:"city" bson:"city"`
}
  

Из-за некоторых проблем с совместимостью между предыдущей сборкой и последней еще не выпущенной сборкой я хочу убедиться, что если кто-то публикует данные json, которые декодируются с использованием этой структуры, он должен иметь возможность использовать либо ‘zipcode’, либо ‘pincode’ в качестве имени поля в своем json. Но когда это значение записывается в мою базу данных, имя поля должно быть только ‘zipcode’.

Короче говоря,

 {
"city": "Mumbai",
"zipcode": "400001"
}
  

или

 {
"city": "Mumbai",
"pincode": "400001"
}
  

должны ли оба отображаться внутри базы данных как —

 {
"city": "Mumbai",
"zipcode": "400001"
}
  

Как мне это разрешить?

Ответ №1:

Вы можете использовать оба поля в качестве указателя на строку:

 type Address struct {
    AddressLine1 string        `json:"addressLine1" bson:"addressLine1"`
    AddressLine2 string        `json:"addressLine2" bson:"addressLine2"`
    Landmark     string        `json:"landmark" bson:"landmark"`
    Zipcode      *string       `json:"zipcode,omitempty" bson:"zipcode"`
    Pincode      *string       `json:"pincode,omitempty" bson:"zipcode"`
    City         string        `json:"city" bson:"city"`
}
  

Как вы можете заметить, мы используем omitempty в теге json, поэтому, если одно из полей отсутствует в json, оно будет проигнорировано как нулевой указатель и не будет присутствовать после Marshal() или Unmarshal()

Редактировать:

В этом случае все, что нам нужно сделать, это реализовать метод, UnmarshalJSON([]byte) error удовлетворяющий интерфейсу Unmarshaler, метод json.Unmarshal() всегда будет пытаться вызвать этот метод, и мы можем добавить нашу собственную логику после Unmarshal структуры, в этом случае мы хотим знать, установлен ли pincode, если он назначен zipcode: полный примерздесь: https://play.golang.org/p/zAOPMtCwBs

 type Address struct {
    AddressLine1 string  `json:"addressLine1" bson:"addressLine1"`
    AddressLine2 string  `json:"addressLine2" bson:"addressLine2"`
    Landmark     string  `json:"landmark" bson:"landmark"`
    Zipcode      *string `json:"zipcode,omitempty" bson:"zipcode"`
    Pincode      *string `json:"pincode,omitempty"`
    City         string  `json:"city" bson:"city"`
}

// private alias of Address to avoid recursion in UnmarshalJSON()
type address Address

func (a *Address) UnmarshalJSON(data []byte) error {
    b := address{}
    if err := json.Unmarshal(data, amp;b); err != nil {
        return nil
    }
    *a = Address(b) // convert the alias to address

    if a.Pincode != nil amp;amp; a.Zipcode == nil {
        a.Zipcode = a.Pincode
        a.Pincode = nil // unset pincode
    }

    return nil
}
  

Обратите внимание, что почтовый индекс поля имеет тег bson, а Pincode нет, также мы должны создать псевдоним типа address, чтобы избежать рекурсивного вызова UnmarshalJSON

Комментарии:

1. Вы правы. Но если данные post содержат ‘pincode’, я все равно хочу, чтобы конечное имя поля в БД было ‘zipcode’.

2. Да, похоже, это правильный путь! Кстати, даже если мы не используем *string и используем omitempty , поле будет проигнорировано правильно. Если мы не маршалируем или не отменяем маршалирование, в этом случае оно будет существовать, но будет пустым. Я правильно понимаю? Спасибо, что уделили время ответу в любом случае!

3. Я попробовал и получил дублированный с ошибкой ключ ‘zipcode’ в утилите struct. Обратитесь к любым идеям, что происходит не так?

4. Опс, похоже, что ваша библиотека не допускает дублирования полей bson , в этом случае мы должны персонализировать наш процесс удаления. Смотрите новое редактирование

5. Большое вам спасибо за подробный ответ @yandry-pozo