2016-10-12 6 views
1

У меня есть-структура, как это -Golang BSON Структура - использовать несколько имен полей для одного поля в формате JSON, но только один для записи в базу данных

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() или распаковать()

Edit:

В этом случае все, что мы должны сделать, это реализовать метод UnmarshalJSON([]byte) error удовлетворить интерфейс Unmarshaler, метод json.Unmarshal() всегда будет пытаться вызвать этот метод, и мы можем добавить собственную логику после того, как распаковать в-структуру, в этом случае мы хотим знать, если пинкод решается, если это мы отнесли к почтовому индексу: полный пример здесь: 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, &b); err != nil { 
     return nil 
    } 
    *a = Address(b) // convert the alias to address 

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

    return nil 
} 

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

+0

Вы правы. Но если данные сообщения содержат «pincode», я все равно хочу, чтобы конечное имя поля в db было «zipcode». –

+0

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

+0

Я попробовал и получил ошибку - Дублированный ключ «zipcode» в утилите struct.Address Любые идеи, что пойдет не так? –

 Смежные вопросы

  • Нет связанных вопросов^_^