gojsonq, ежедневная библиотека для Go

Go

Введение

Каждый разработчик, будь то фронтенд или бэкенд, регулярно использует JSON в своей повседневной работе. JSON — это очень простой формат обмена данными. По сравнению с XML он более гибкий, легкий и простой в использовании. JSON тожеRESTful APIРекомендуемый формат. Иногда нам нужно прочитать только определенные поля в JSON. Если вы вручную разбираете и читаете слой за слоем, это становится чрезвычайно громоздким. Особенно если уровень вложенности очень глубокий. Сегодня мы представляемgojsonq. Это может помочь нам очень удобно манипулировать JSON.

быстрый в использовании

Сначала установите:

$ go get github.com/thedevsaddam/gojsonq

После использования:

package main

import (
  "fmt"

  "github.com/thedevsaddam/gojsonq"
)

func main() {
  content := `{
  "user": {
    "name": "dj",
    "age": 18,
    "address": {
      "provice": "shanghai",
      "district": "xuhui"
    },
    "hobbies":["chess", "programming", "game"]
  }
}`

  gq := gojsonq.New().FromString(content)
  district := gq.Find("user.address.district")
  fmt.Println(district)

  gq.Reset()

  hobby := gq.Find("user.hobbies.[0]")
  fmt.Println(hobby)
}

Операция очень проста:

  • первый звонокgojsonq.New()СоздаватьJSONQОбъект;
  • Затем вы можете использовать методы этого типа для запроса свойств.

В приведенном выше коде мы напрямую читаем самый внутреннийdistrictценность иhobbiesПервый элемент массива! между слоями.разделены, если это массив, передать после поля атрибута.[index]читать нижний индекс какindexЭлементы. Этот метод может обеспечить очень гибкое чтение.

Обратите внимание на деталь: после запроса мы вручную вызываем один разReset()метод. так какJSONQобъект звонитFindметод, текущий узел будет записан во внутреннюю память, и следующий запрос начнется с последнего искомого узла. То есть, если мы закомментируемjq.Reset(),секундаFind()Метод фактически ищетuser.address.district.user.hobbies.[0], естественно возвратnil. Кроме,gojsonqПредусмотрен и другой способ. Если вы хотите сохранить некоторую информацию о состоянии текущего запроса, вы можете вызватьJSONQизCopyМетод возвращает объект в его начальном состоянии, который будет совместно использовать базовую строку JSON и проанализированный объект. вышеgq.Reset()Его можно заменить следующей строкой кода:

gpCopy := gp.Copy()

можно использовать позжеgpCopyЗапросhobbies.

этоgojsonqОсобенность библиотеки, но она тоже доставляет много хлопот новичкам и требует особого внимания. По факту,JSONQМногие из предоставленных методов изменяют текущий узел, как мы увидим более четко в следующем разделе.

источник данных

Помимо загрузки из строки,jsonqТакже разрешает файлы иio.Readerчитать содержимое. использовать отдельноJSONQобъектFileиReaderметод:

func main() {
  gq := gojsonq.New().File("./data.json")

  fmt.Println(gq.Find("items.[1].price"))
}

Эффект такой же, как и у следующей программы:

func main() {
  file, err := os.OpenFile("./data.json", os.O_RDONLY, 0666)
  if err != nil {
    log.Fatal(err)
  }

  gq := gojsonq.New().Reader(file)

  fmt.Println(gq.Find("items.[1].price"))
}

Для удобства последующей демонстрации я построилdata.jsonдокумент:

{
  "name": "shopping cart",
  "description": "List of items in your cart",
  "prices": ["2400", "2100", "1200", "400.87", "89.90", "150.10"],
  "items": [
    {
      "id": 1,
      "name": "Apple",
      "count": 2,
      "price": 12
    },
    {
      "id": 2,
      "name": "Notebook",
      "count": 10,
      "price": 3
    },
    {
      "id": 3,
      "name": "Pencil",
      "count": 5,
      "price": 1
    },
    {
      "id": 4,
      "name": "Camera",
      "count": 1,
      "price": 1750
    },
    {
      "id": null,
      "name": "Invalid Item",
      "count": 1,
      "price": 12000
    }
  ]
}

Расширенный поиск

gojsonqУникальность его в том, что он может выполнять условные запросы, такие как SQL, вы можете выбирать, какие поля возвращать, и вы можете делать некоторую агрегированную статистику.

Отображение полей

Иногда нам нужны только несколько полей в объекте, тогда мы можем использоватьSelectУкажите, какие поля возвращаются, а остальные нет:

func main() {
  r := gojsonq.New().File("./data.json").From("items").Select("id", "name").Get()
  data, _ := json.MarshalIndent(r, "", "  ")
  fmt.Println(string(data))
}

будет выводить толькоidиnameПоле:

$ go run main.go
[
  {
    "id": 1,
    "name": "Apple"
  },
  {
    "id": 2,
    "name": "Notebook"
  },
  {
    "id": 3,
    "name": "Pencil"
  },
  {
    "id": 4,
    "name": "Camera"
  },
  {
    "id": null,
    "name": "Invalid Item"
  }
]

Чтобы отобразить немного более интуитивно понятным, я используюjson.MarshalIndent()Сделал некоторые украшения на выходе.

Это похоже на SQL?Select id,name From items...

Вот введениеFromметод, функция этого метода состоит в том, чтобы переместить текущий узел в указанную позицию. Выше также упоминалось, что записывается положение текущего узла. Например, в приведенном выше коде мы сначала перемещаем текущий узел вitems, все последующие запросы и операции агрегирования выполняются для этого массива. ФактическиFindметод вызывается внутриFrom:

// src/github.com/thedevsaddam/gojsonq/jsonq.go
func (j *JSONQ) Find(path string) interface{} {
  return j.From(path).Get()
}

func (j *JSONQ) From(node string) *JSONQ {
  j.node = node
  v, err := getNestedValue(j.jsonContent, node, j.option.separator)
  if err != nil {
    j.addError(err)
  }
  // ============= 注意这一行,记住当前节点位置
  j.jsonContent = v
  return j
}

Наконец, вы должны позвонитьGet(), который объединяет все условия и выполняет запрос, возвращая результат.

Условный запрос

имеютSelectиFrom, как не могWhereШерстяная ткань?gojsonqкоторый предоставилWhereЕсть много методов, и мы, вероятно, рассмотрим только некоторые из них.

прежде всего,Where(key, op, val), это общийWhereсостояние, выражающееkeyиvalЭто удовлетвореноopсвязь.opВстроенных около 20, а также поддерживается настройка. Например=значит равный,!=значит не ждать,startsWithвыражатьvalтак или иначеkeyпрефиксы полей и т.д.;

Многие другие условия являютсяWhereособые случаи, такие какWhereIn(key, val)эквивалентноWhere(key, "in", val),WhereStartsWith(key, val)эквивалентноWhere(key, "startsWith", val).

по умолчанию,WhereусловияAndподключено, мы можем пройтиOrWhereбудь как будетOrсоединять:

func main() {
  gq := gojsonq.New().File("./data.json")

  r := gq.From("items").Select("id", "name").
    Where("id", "=", 1).OrWhere("id", "=", 2).Get()
  fmt.Println(r)

  gq.Reset()

  r = gq.From("items").Select("id", "name", "count").
    Where("count", ">", 1).Where("price", "<", 100).Get()
  fmt.Println(r)
}

Первый запрос выше находитid1или2 записи. Второй запрос, найтиcountБольше 1и priceМенее 100 записей.

Укажите смещение и количество возвращаемых записей

Иногда мы хотим разбить на страницы и вернуть первые 3 записи по первому запросу и следующие 3 записи по второму запросу. мы можем использоватьJSONQобъектOffsetиLimitметод, чтобы указать смещение и количество возвращаемых записей:

func main() {
  gq := gojsonq.New().File("./data.json")

  r1 := gq.From("items").Select("id", "name").Offset(0).Limit(3).Get()
  fmt.Println("First Page:", r1)

  gq.Reset()

  r2 := gq.From("items").Select("id", "name").Offset(3).Limit(3).Get()
  fmt.Println("Second Page:", r2)
}

Посмотрим на результат работы:

$ go run main.go
First Page: [map[id:1 name:Apple] map[id:2 name:Notebook] map[id:3 name:Pencil]]
Second Page: [map[id:4 name:Camera] map[id:<nil> name:Invalid Item]]

Сводная статистика

Мы также можем сделать простую статистику по некоторым полям, вычислить сумму, среднее значение, максимум, минимум и т. д.:

func main() {
  gq := gojsonq.New().File("./data.json").From("items")

  fmt.Println("Total Count:", gq.Sum("count"))
  fmt.Println("Min Price:", gq.Min("price"))
  fmt.Println("Max Price:", gq.Max("price"))
  fmt.Println("Avg Price:", gq.Avg("price"))
}

Выше подсчитывается общее количество, минимальная цена, максимальная цена и средняя цена товара.

Ни один из методов класса агрегированной статистики не изменит указатель текущего узла, поэтомуJSONQОбъекты можно использовать повторно!

Данные также можно группировать и сортировать:

func main() {
  gq := gojsonq.New().File("./data.json")

  fmt.Println(gq.From("items").GroupBy("price").Get())
  gq.Reset()
  fmt.Println(gq.From("items").SortBy("price", "desc").Get())
}

Другие форматы

по умолчанию,gojsonqРазбирать данные в формате JSON. Мы также можем установить другие парсеры форматов, чтобыgojsonqДругие форматы данных могут быть обработаны:

func main() {
  jq := gojsonq.New(gojsonq.SetDecoder(&yamlDecoder{})).File("./data.yaml")
  jq.From("items").Where("price", "<=", 500)
  fmt.Printf("%v\n", jq.First())
}

type yamlDecoder struct {
}

func (i *yamlDecoder) Decode(data []byte, v interface{}) error {
  bb, err := yaml.YAMLToJSON(data)
  if err != nil {
    return err
  }
  return json.Unmarshal(bb, &v)
}

Приведенный выше код используетсяyamlБиблиотеки, требующие дополнительной установки:

$ go get github.com/ghodss/yaml

Парсеру нужно только реализоватьgojsonq.Decoderинтерфейс, может быть установлен какgojsonq, так что любой формат может быть обработан:

// src/github.com/thedevsaddam/gojsonq/decoder.go
type Decoder interface {
  Decode(data []byte, v interface{}) error
}

Суммировать

gojsonqЕсть также расширенные функции, такие как настройкаWhereТип операции , принимает первое, последнее, N-е значение и т. д. Если вам интересно, вы можете провести собственное исследование~

Если вы найдете забавную и простую в использовании языковую библиотеку Go, вы можете отправить сообщение о проблеме в ежедневной библиотеке Go GitHub😄

Ссылаться на

  1. gojsonq GitHub:GitHub.com/the vs AD хит…
  2. Перейти на ежедневный репозиторий GitHub:GitHub.com/Darenjun/go-of…

я

мой блог

Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись WeChat [GoUpUp], учитесь вместе и добивайтесь прогресса вместе ~

Эта статья опубликована в блогеOpenWriteвыпуск!