#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