Compartilhar via


Introdução ao JSON – Linguagem de consulta no Cosmos DB (no Azure e fabric)

Trabalhar com JSON (JavaScript Object Notation) está no centro da linguagem de consulta. Os itens são armazenados como JSON e todas as consultas, expressões e tipos são projetados para funcionar com dados JSON. Para obter mais informações sobre o JSON em si, consulte a especificação JSON formal.

Aqui estão algumas coisas importantes para saber sobre JSON neste contexto:

  • Objetos JSON sempre começam com {}.
  • As propriedades podem ser aninhadas entre si.
  • Os valores de propriedade podem ser matrizes.
  • Os nomes de propriedades diferenciam maiúsculas de minúsculas.
  • Os nomes de propriedade podem ser qualquer cadeia de caracteres, mesmo com espaços ou caracteres especiais.

Propriedades aninhadas

Você pode acessar propriedades JSON aninhadas usando notação de ponto. Isso funciona como acessar propriedades na maioria das linguagens de programação.

Aqui está um documento de exemplo com JSON aninhado:

[
  {
    "name": "Heatker Women's Jacket",
    "category": "apparel",
    "slug": "heatker-women-s-jacket",
    "sizes": [
      {
        "key": "s",
        "description": "Small"
      }
    ],
    "metadata": {
      "link": "https://www.adventure-works.com/heatker-women-s-jacket/68719520138.p"
    }
  }
]

Em seguida, você pode projetar as mesmas propriedades aninhadas em suas consultas:

SELECT
  p.name,
  p.category,
  p.metadata.link
FROM
  products p
WHERE
  p.name = "Heatker Women's Jacket"

E você obteria essa saída esperada:

[
  {
    "name": "Heatker Women's Jacket",
    "category": "apparel",
    "link": "https://www.adventure-works.com/heatker-women-s-jacket/68719520138.p"
  }
]

Matrizes e conjuntos

O JSON dá suporte a matrizes e você pode trabalhar com elas em suas consultas. Para acessar um elemento específico, use sua posição na matriz.

Usando o mesmo exemplo da seção anterior, podemos acessar um item na matriz usando seu índice. Por exemplo, se quisermos acessar o primeiro item na matriz, usaremos um índice de 0 como ele é um sistema de índice baseado em zero para matrizes na linguagem de consulta:

SELECT
  p.name,
  p.sizes[0].description AS defaultSize
FROM
  products p
WHERE
  p.name = "Heatker Women's Jacket"

Essa consulta resulta no seguinte objeto JSON:

[
  {
    "name": "Heatker Women's Jacket",
    "defaultSize": "Small"
  }
]

Agora, vamos considerar um exemplo com uma matriz maior:

[
  {
    "name": "Vencon Kid's Coat",
    "category": "apparel",
    "slug": "vencon-kid-s-coat",
    "colors": [
      "cardinal",
      "disco"
    ],
    "sizes": [
      {
        "key": "m",
        "description": "Medium"
      },
      {
        "key": "l",
        "description": "Large"
      },
      {
        "key": "xl",
        "description": "Extra Large"
      }
    ]
  }
]

Muitas vezes, você deseja usar uma subconsulta ou uma autojunção para trabalhar com todos os elementos em uma matriz. Por exemplo, para obter cada cor como uma linha separada:

SELECT
  p.name,
  c AS color
FROM
  products p
JOIN
  c IN p.colors
WHERE
  p.name = "Vencon Kid's Coat"

O que resultaria em uma matriz JSON como esta:

[
  {
    "name": "Vencon Kid's Coat",
    "color": "cardinal"
  },
  {
    "name": "Vencon Kid's Coat",
    "color": "disco"
  }
]

Para verificar se existe um determinado valor em uma matriz, você pode usar a matriz no filtro após a WHERE palavra-chave. Este exemplo usa uma subconsulta para filtrar os itens da matriz:

SELECT VALUE
  p.name
FROM
  products p
WHERE
  EXISTS(SELECT VALUE
    c
  FROM
    c IN p.sizes
  WHERE
    c.description LIKE "%Large")

Essa consulta resulta em uma matriz JSON simples de cadeias de caracteres, que incluiria o item no exemplo:

[
  ...,
  "Vencon Kid's Coat"
  ...
]

Por fim, você pode construir matrizes combinando várias propriedades. Neste exemplo, várias propriedades são combinadas para formar uma metadata matriz:

SELECT
  p.name,
  [
    p.category,
    p.slug,
    p.metadata.link
  ] AS metadata
FROM
  products p
WHERE
  p.name = "Heatker Women's Jacket"
[
  {
    "name": "Heatker Women's Jacket",
    "metadata": [
      "apparel",
      "heatker-women-s-jacket",
      "https://www.adventure-works.com/heatker-women-s-jacket/68719520138.p"
    ]
  }
]

Iteração

A linguagem de consulta dá suporte à iteração em matrizes JSON usando a IN palavra-chave na origem FROM .

Considere este conjunto de dados de exemplo:

[
  {
    "name": "Pila Swimsuit",
    "colors": [
      "regal-blue",
      "rose-bud-cherry"
    ],
    "sizes": [
      {
        "key": "m",
        "description": "Medium"
      },
      {
        "key": "l",
        "description": "Large"
      },
      {
        "key": "xl",
        "description": "Extra Large"
      }
    ]
  },
  {
    "name": "Makay Bikini",
    "colors": [
      "starship"
    ],
    "sizes": [
      {
        "key": "s",
        "description": "Small"
      },
      {
        "key": "m",
        "description": "Medium"
      },
      {
        "key": "l",
        "description": "Large"
      }
    ]
  }
]

Este primeiro exemplo usa a IN palavra-chave para executar iteração sobre a colors propriedade de cada produto:

SELECT
  *
FROM
  p IN p.colors
[
  "regal-blue",
  "rose-bud-cherry",
  "starship"
]

Você também pode filtrar entradas individuais na matriz usando a WHERE cláusula. Neste exemplo, a sizes propriedade é filtrada:

SELECT
  p.key
FROM
  p IN p.sizes
WHERE
  p.description LIKE "%Large"
[
  {
    "key": "l"
  },
  {
    "key": "xl"
  },
  {
    "key": "l"
  }
]

Usando a mesma IN palavra-chave, você pode agregar sobre o resultado de uma iteração de matriz. Neste exemplo, a consulta retorna a contagem do número de marcas resumidas em todos os itens no contêiner:

SELECT VALUE
  COUNT(1)
FROM
  p IN p.sizes

Observação

Ao usar a IN palavra-chave para iteração, você não pode filtrar ou projetar nenhuma propriedade fora da matriz. Em vez disso, você usa auto-junções.

Valores nulos e indefinidos

Se uma propriedade não estiver presente em um documento, seu valor será undefined. Se uma propriedade estiver presente, mas definida como null, esse será um valor definido explicitamente. A distinção entre null e undefined é uma distinção importante que pode causar confusão em consultas.

Por exemplo, esse objeto JSON teria um valor undefined para a sku propriedade porque a propriedade nunca foi definida:

[
  {
    "name": "Witalica helmet",
    "category": "gear",
  }
]

Esse objeto JSON teria um valor para null a mesma propriedade porque a propriedade ainda não está definida com um valor:

[
  {
    "name": "Witalica helmet",
    "category": "gear",
    "sku": null
  }
]

Há funções internas para verificar esses casos:

  • IS_NULL verifica se uma propriedade é null.
  • IS_DEFINED verifica se existe uma propriedade (não undefinedé).

Veja como você pode verificar os dois:

SELECT
  IS_DEFINED(p.sku) AS isSkuDefined,
  IS_NULL(p.sku) AS isSkuDefinedButNull
FROM
  products p

Notação de colchete

Embora a maioria dos exemplos use notação de ponto para especificar propriedades, você sempre pode especificar as mesmas propriedades usando notação de colchete .

Vamos começar com um objeto simples com um objeto aninhado como o valor da metadata propriedade:

[
  {
    "name": "Hikomo Sandals",
    "metadata": {
      "link": "https://www.adventure-works.com/hikomo-sandals/68719519305.p"
    }
  }
]

Para esse objeto, podemos referenciar a metadata.link propriedade de três maneiras distintas usando combinações de notação de ponto e colchete :

SELECT
  p.metadata.link AS metadataLinkDotNotation,
  p["metadata"]["link"] AS metadataLinkBracketNotation,
  p.metadata["link"] AS metadataLinkMixedNotation
FROM
  products p
WHERE
  p.name = "Hikomo Sandals"
[
  {
    "metadataLinkDotNotation": "https://www.adventure-works.com/hikomo-sandals/68719519305.p",
    "metadataLinkBracketNotation": "https://www.adventure-works.com/hikomo-sandals/68719519305.p",
    "metadataLinkMixedNotation": "https://www.adventure-works.com/hikomo-sandals/68719519305.p"
  }
]

Dica

Se um nome de propriedade tiver espaços, caracteres especiais ou corresponder a uma palavra reservada, você deverá usar a notação de colchete para especificar a propriedade.

Expressões JSON

Você pode criar objetos JSON diretamente nos resultados da consulta. Vamos começar com essa matriz JSON como exemplo:

[
  {
    "name": "Diannis Watch",
    "category": "apparel",
    "detailCategory": "apparel-accessories-watches",
    "slug": "diannis-watch",
    "sku": "64801",
    "price": 98,
    "quantity": 159
  },
  {
    "name": "Confira Watch",
    "category": "apparel",
    "detailCategory": "apparel-accessories-watches",
    "slug": "confira-watch",
    "sku": "64800",
    "price": 105,
    "quantity": 193
  }
]

Usando a sintaxe mais simples, você pode influenciar os nomes de propriedade de um objeto JSON relativamente simples usando colchetes angulares ({/}) e a sintaxe JSON inserida em uma consulta NoSQL:

SELECT {
  "brandName": p.name,
  "department": p.category
}
FROM
  products p
WHERE
  p.detailCategory = "apparel-accessories-watches"
[
  {
    "$1": {
      "brandName": "Diannis Watch",
      "department": "apparel"
    }
  },
  {
    "$1": {
      "brandName": "Confira Watch",
      "department": "apparel"
    }
  }
]

No exemplo anterior, o resultado tinha um nome $1 inferido porque um nome explícito não estava definido. Neste próximo exemplo, o resultado tem um nome explícito definido product usando um alias:

SELECT {
  "brandName": p.name,
  "department": p.category
} AS product
FROM
  products p
WHERE
  p.detailCategory = "apparel-accessories-watches"
[
  {
    "product": {
      "brandName": "Diannis Watch",
      "department": "apparel"
    }
  },
  {
    "product": {
      "brandName": "Confira Watch",
      "department": "apparel"
    }
  }
]

Como alternativa, o resultado pode ser mesclado usando a VALUE palavra-chave em uma SELECT VALUE instrução:

SELECT VALUE {
  "brandName": p.name,
  "department": p.category
}
FROM
  products p
WHERE
  p.detailCategory = "apparel-accessories-watches"
[
  {
    "brandName": "Diannis Watch",
    "department": "apparel"
  },
  {
    "brandName": "Confira Watch",
    "department": "apparel"
  }
]

Indo ainda mais longe, você pode usar a sintaxe JSON para "remodelar" o objeto JSON de resultado para incluir matrizes, subobjetos e outros constructos JSON que podem não ser explicitamente definidos no item original. Essa técnica será útil se o aplicativo cliente estiver esperando dados em um esquema específico que não corresponda aos dados subjacentes.

Considere este esquema JSON, por exemplo:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "required": [
    "id",
    "category",
    "financial"
  ],
  "properties": {
    "id": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "category": {
      "type": "object",
      "properties": {
        "department": {
          "type": "string"
        },
        "section": {
          "type": "string"
        }
      },
      "required": [
        "department"
      ]
    },
    "inventory": {
      "type": "object",
      "properties": {
        "stock": {
          "type": "number"
        }
      }
    },
    "financial": {
      "type": "object",
      "properties": {
        "listPrice": {
          "type": "number"
        }
      },
      "required": [
        "listPrice"
      ]
    }
  }
}

Esse esquema permitiria um objeto JSON estruturado neste formato:

[
  {
    "id": "[string]",
    "name": "[string]",
    "category": {
      "department": "[string]",
      "section": "[string]"
    },
    "inventory": {
      "stock": [number]
    },
    "financial": {
      "listPrice": [number]
    }
  }
]

Essa consulta NoSQL remapea os objetos originais para estar em conformidade com este novo esquema:

SELECT VALUE {
  "id": p.sku,
  "name": p.name,
  "category": {
    "department": p.category,
    "section": p.detailCategory
  },
  "inventory": {
    "stock": p.quantity
  },
  "financial": {
    "listPrice": p.price
  }
}
FROM
  products p
WHERE
  p.detailCategory = "apparel-accessories-watches"
[
  {
    "id": "64801",
    "name": "Diannis Watch",
    "category": {
      "department": "apparel",
      "section": "apparel-accessories-watches"
    },
    "inventory": {
      "stock": 159
    },
    "financial": {
      "listPrice": 98
    }
  },
  {
    "id": "64800",
    "name": "Confira Watch",
    "category": {
      "department": "apparel",
      "section": "apparel-accessories-watches"
    },
    "inventory": {
      "stock": 193
    },
    "financial": {
      "listPrice": 105
    }
  }
]

Aliases de contêiner

Por padrão, o termo usado após a FROM palavra-chave faz referência ao contêiner que é o destino da consulta. O termo em si NÃO é necessário para corresponder ao nome do contêiner.

Por exemplo, se o contêiner for nomeado products, qualquer uma dessas consultas funcionará bem e todas referenciarão o products contêiner, desde que esse contêiner seja o destino da consulta:

SELECT
  products.id
FROM
  products
SELECT
  p.id
FROM
  p
SELECT
  items.id
FROM
  items
SELECT
  targetContainer.id
FROM
  targetContainer

Para tornar sua consulta NoSQL mais concisa, é comum alias o nome do contêiner com um nome mais curto. O aliasing pode ser feito usando a AS palavra-chave:

SELECT
  p.id
FROM
  products AS p

A linguagem de consulta também tem uma sintaxe abreviada em que o alias pode ser definido imediatamente após a referência do contêiner de destino sem a AS palavra-chave. Essa abreviação é funcionalmente equivalente ao uso da AS palavra-chave:

SELECT
  p.id
FROM
  products p

Aliases de propriedade

Você também pode renomear campos em seus resultados usando aliases definidos com a mesma AS palavra-chave. Para os próximos exemplos, considere esses dados de exemplo:

[
  {
    "name": "Oceabelle Scarf",
    "detailCategory": "apparel-accessories-scarfs-and-socks",
    "metadata": {
      "link": "https://www.adventure-works.com/oceabelle-scarf/68719522190.p"
    }
  },
  {
    "name": "Shinity Socks",
    "detailCategory": "apparel-accessories-scarfs-and-socks",
    "metadata": {
      "link": "https://www.adventure-works.com/shinity-socks/68719522161.p"
    }
  },
  {
    "name": "Horric Socks",
    "detailCategory": "apparel-accessories-scarfs-and-socks",
    "metadata": {
      "link": "https://www.adventure-works.com/horric-socks/68719522177.p"
    }
  }
]

Neste primeiro exemplo, o alias metadataLink é usado para o metadata.link valor da propriedade:

SELECT
  p.name,
  p.metadata.link AS metadataLink
FROM
  products p
[
  {
    "name": "Oceabelle Scarf",
    "metadataLink": "https://www.adventure-works.com/oceabelle-scarf/68719522190.p"
  },
  {
    "name": "Shinity Socks",
    "metadataLink": "https://www.adventure-works.com/shinity-socks/68719522161.p"
  },
  {
    "name": "Horric Socks",
    "metadataLink": "https://www.adventure-works.com/horric-socks/68719522177.p"
  }
]

Importante

Você não pode usar o aliasing para projetar um valor como um nome de propriedade com um espaço, caractere especial ou palavra reservada. Se você quiser alterar a projeção de um valor para, por exemplo, ter um nome de propriedade com um espaço, deverá usar uma expressão JSON.

Por exemplo

SELECT VALUE {
  "product name": p.name,
  "from": p.metadata.link,
  "detail/category": p.detailCategory
}
FROM
  products p
WHERE
  p.detailCategory = "apparel-accessories-scarfs-and-socks"
[
  {
    "product name": "Oceabelle Scarf",
    "from": "https://www.adventure-works.com/oceabelle-scarf/68719522190.p",
    "detail/category": "apparel-accessories-scarfs-and-socks"
  },
  {
    "product name": "Shinity Socks",
    "from": "https://www.adventure-works.com/shinity-socks/68719522161.p",
    "detail/category": "apparel-accessories-scarfs-and-socks"
  },
  {
    "product name": "Horric Socks",
    "from": "https://www.adventure-works.com/horric-socks/68719522177.p",
    "detail/category": "apparel-accessories-scarfs-and-socks"
  }
]

Se uma consulta NoSQL tiver duas propriedades com o mesmo nome, use aliases para renomear uma ou ambas as propriedades para que elas sejam desambiguadas no resultado projetado.

Considere este exemplo de dados:

[
  {
    "name": "Oceabelle Scarf",
    "detailCategory": "apparel-accessories-scarfs-and-socks",
    "sizes": [
      {
        "key": "s"
      },
      ...
    ],
    "tags": [
      ...
    ]
  },
  {
    "name": "Shinity Socks",
    "detailCategory": "apparel-accessories-scarfs-and-socks",
    "sizes": [
      ...
      {
        "key": "10"
      },
      ...
    ],
    "tags": [
      ...
      {
        "key": "length"
      }
    ]
  },
  {
    "name": "Horric Socks",
    "detailCategory": "apparel-accessories-scarfs-and-socks",
    "sizes": [
      ...
      {
        "key": "7"
      },
      ...
    ],
    "tags": [
      {
        "key": "fabric"
      },
      ...
    ]
  }
]

Observação

Neste exemplo de dados e no resultado da consulta, várias propriedades e valores foram removidos para fins de brevidade.

Essa consulta NoSQL retorna as propriedades e p.tags[].key o p.sizes[].key resultado entre produtos, mas alias cada key propriedade para evitar colisões:

SELECT
  p.name,
  s.key AS sizeKey,
  t.key AS tagKey
FROM
  products p
JOIN
  s IN p.sizes
JOIN
  t in p.tags
WHERE
  p.detailCategory = "apparel-accessories-scarfs-and-socks"
[
  {
    "name": "Oceabelle Scarf",
    "sizeKey": "s",
    "tagKey": "fabric"
  },
  ...
  {
    "name": "Shinity Socks",
    "sizeKey": "10",
    "tagKey": "length"
  },
  ...
  {
    "name": "Horric Socks",
    "sizeKey": "7",
    "tagKey": "fabric"
  }
]