Partilhar via


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

Trabalhar com JavaScript Object Notation (JSON) 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 trabalhar com dados JSON. Para obter mais informações sobre o próprio JSON, consulte a especificação JSON formal.

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

  • Os objetos JSON sempre começam com { e terminam com }.
  • As propriedades podem ser aninhadas umas nas outras.
  • Os valores de propriedade podem ser matrizes.
  • Os nomes de propriedade são sensíveis a maiúsculas e 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 exatamente como acessar propriedades na maioria das linguagens de programação.

Aqui está um exemplo de documento 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 esta 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

JSON suporta matrizes, e você pode trabalhar com eles 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 uma vez que é um sistema de índice baseado em zero para matrizes na linguagem de 0 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 associação automática 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 um determinado valor existe 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"
  ...
]

Finalmente, 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"
    ]
  }
]

Iteration

A linguagem de consulta suporta iteração sobre matrizes JSON usando a INFROM palavra-chave na fonte.

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 palavra-chave para executar iteração IN 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 tags somadas 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 é um valor explicitamente definido. A distinção entre null e undefined é uma distinção importante que pode causar confusão nas consultas.

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

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

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

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

Existem funções incorporadas para verificar estes casos:

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

Veja como você pode verificar ambos:

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

Notação entre parênteses

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

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"
  }
]

Sugestão

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

Expressões JSON

Você pode criar objetos JSON diretamente nos resultados da consulta. Vamos começar com esta 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 direta, você pode influenciar os nomes de propriedade de um objeto JSON relativamente plano usando colchetes angulares ({/}) e a sintaxe JSON incorporada 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 inferido porque $1 um nome explícito não estava definido. Neste próximo exemplo, o resultado tem um nome explícito de product definido 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 nivelado 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 resultante para incluir matrizes, subobjetos e outras construções JSON que podem não estar explicitamente definidas no item original. Essa técnica é ú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]
    }
  }
]

Esta consulta NoSQL remapeia o(s) objeto(s) original(is) para ser compatível 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 farão referência ao 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 usar o alias do 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 onde o alias pode ser definido imediatamente após a referência do contêiner de destino sem a AS palavra-chave. Esta abreviatura é 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 estes 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 metadataLink alias é 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

Não é possível usar 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 estes dados de exemplo:

[
  {
    "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 maior brevidade.

Esta consulta NoSQL retorna as p.sizes[].key propriedades e p.tags[].key no 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"
  }
]