Compartir vía


Introducción a JSON: lenguaje de consulta en Cosmos DB (en Azure y Fabric)

Trabajar con notación de objetos JavaScript (JSON) es el núcleo del lenguaje de consulta. Los elementos se almacenan como JSON y todas las consultas, expresiones y tipos están diseñados para trabajar con datos JSON. Para obtener más información sobre JSON en sí, consulte la especificación JSON formal.

Estos son algunos aspectos clave que se deben conocer sobre JSON en este contexto:

  • Los objetos JSON siempre comienzan con { y terminan con }.
  • Las propiedades se pueden anidar entre sí.
  • Los valores de propiedad pueden ser matrices.
  • Los nombres de propiedad distinguen entre mayúsculas y minúsculas.
  • Los nombres de propiedad pueden ser cualquier cadena, incluso con espacios o caracteres especiales.

Propiedades anidadas

Puede acceder a las propiedades JSON anidadas mediante la notación de puntos. Esto funciona igual que el acceso a propiedades en la mayoría de los lenguajes de programación.

Este es un documento de ejemplo con JSON anidado:

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

A continuación, puede proyectar las mismas propiedades anidadas en las consultas:

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

Y obtendría esta salida esperada:

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

Matrices y conjuntos

JSON admite matrices y puede trabajar con ellas en las consultas. Para acceder a un elemento específico, use su posición en la matriz.

Con el mismo ejemplo de la sección anterior, podemos acceder a un elemento de la matriz mediante su índice. Por ejemplo, si queremos tener acceso al primer elemento de la matriz, usaríamos un índice de 0 , ya que es un sistema de índices de base cero para matrices en el lenguaje de consulta:

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

Esta consulta da como resultado el siguiente objeto JSON:

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

Ahora, vamos a considerar un ejemplo con una matriz mayor:

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

A menudo, quiere usar una subconsulta o una autocombinación para trabajar con todos los elementos de una matriz. Por ejemplo, para obtener cada color como una fila independiente:

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

Lo que daría lugar a una matriz JSON como esta:

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

Para comprobar si existe un valor determinado en una matriz, puede usar la matriz en el filtro después de la WHERE palabra clave . En este ejemplo se usa una subconsulta para filtrar los elementos de la matriz:

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

Esta consulta da como resultado una matriz JSON plana de cadenas, que incluiría el elemento en el ejemplo:

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

Por último, puede construir matrices mediante la combinación de varias propiedades. En este ejemplo, se combinan varias propiedades para formar una 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"
    ]
  }
]

Iteración

El lenguaje de consulta admite la iteración a través de matrices JSON mediante la IN palabra clave en el FROM origen.

Considere este conjunto de datos de ejemplo:

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

En este primer ejemplo se usa la IN palabra clave para realizar la iteración sobre la colors propiedad de cada producto:

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

También puede filtrar entradas individuales en la matriz mediante la WHERE cláusula . En este ejemplo, la sizes propiedad se filtra:

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

Con la misma IN palabra clave, puede agregar el resultado de una iteración de matriz. En este ejemplo, la consulta devuelve el recuento del número de etiquetas sumadas en todos los elementos del contenedor:

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

Nota:

Al usar la IN palabra clave para la iteración, no se pueden filtrar ni proyectar propiedades fuera de la matriz. En su lugar, se usan autocombinaciones.

Valores NULL y sin definir

Si una propiedad no está presente en un documento, su valor es undefined. Si una propiedad está presente, pero se establece en null, es un valor establecido explícitamente. La distinción entre null y undefined es una distinción importante que puede causar confusión en las consultas.

Por ejemplo, este objeto JSON tendría un valor de undefined para la sku propiedad porque la propiedad nunca se definió:

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

Este objeto JSON tendría un valor de null para la misma propiedad porque la propiedad todavía no está establecida con un valor:

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

Hay funciones integradas para comprobar estos casos:

  • IS_NULL comprueba si una propiedad es null.
  • IS_DEFINED comprueba si existe una propiedad (no undefinedes ).

Aquí se muestra cómo puede comprobar ambos:

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

Notación de corchetes

Aunque la mayoría de los ejemplos usan la notación de puntos para especificar propiedades, siempre puede especificar las mismas propiedades mediante la notación de corchetes .

Comencemos con un objeto simple con un objeto anidado como valor de la metadata propiedad :

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

Para ese objeto, podemos hacer referencia a la metadata.link propiedad de tres maneras distintas mediante combinaciones de notación de punto y corchetes :

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

Sugerencia

Si un nombre de propiedad tiene espacios, caracteres especiales o coincide con una palabra reservada, debe usar la notación de corchetes para especificar la propiedad.

Expresiones JSON

Puede crear objetos JSON directamente en los resultados de la consulta. Comencemos con esta matriz JSON como ejemplo:

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

Con la sintaxis más sencilla, puede influir en los nombres de propiedad de un objeto JSON relativamente plano mediante corchetes angulares ({/}) y la sintaxis JSON incrustada en una 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"
    }
  }
]

En el ejemplo anterior, el resultado tenía un nombre inferido de $1 porque no se definió un nombre explícito. En este ejemplo siguiente, el resultado tiene un nombre explícito de product definido mediante un 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, el resultado se puede aplanar mediante la VALUE palabra clave en una SELECT VALUE instrucción :

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

Además, puede usar la sintaxis JSON para "volver a dar forma" al objeto JSON de resultado para incluir matrices, subobjetos y otras construcciones JSON que podrían no definirse explícitamente en el elemento original. Esta técnica es útil si la aplicación cliente espera datos en un esquema específico que no coincide con los datos subyacentes.

Tenga en cuenta este esquema JSON, por ejemplo:

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

Ese esquema permitiría un objeto JSON estructurado en este formato:

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

Esta consulta NoSQL reasigna el objeto original para que sea compatible con este nuevo 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
    }
  }
]

Alias de contenedor

De forma predeterminada, el término usado después de la FROM palabra clave hace referencia al contenedor que es el destino de la consulta. El propio término NO es necesario para que coincida con el nombre del contenedor.

Por ejemplo, si el contenedor se denomina products, cualquiera de estas consultas funciona correctamente y todo hace referencia al products contenedor siempre que ese contenedor sea el destino de la consulta:

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

Para que la consulta NoSQL sea más concisa, es habitual dar un alias al nombre del contenedor con un nombre más corto. El alias se puede realizar mediante la AS palabra clave :

SELECT
  p.id
FROM
  products AS p

El lenguaje de consulta también tiene una sintaxis abreviada donde el alias se puede definir inmediatamente después de la referencia del contenedor de destino sin la AS palabra clave . Esta abreviatura es funcionalmente equivalente al uso de la AS palabra clave :

SELECT
  p.id
FROM
  products p

Alias de propiedad

También puede cambiar el nombre de los campos de los resultados mediante alias que define con la misma AS palabra clave. Para los ejemplos siguientes, tenga en cuenta estos datos de ejemplo:

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

En este primer ejemplo, el metadataLink alias se usa para el valor de la metadata.link propiedad:

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

No se puede usar el alias para proyectar un valor como un nombre de propiedad con un espacio, un carácter especial o una palabra reservada. Si desea cambiar la proyección de un valor a, por ejemplo, tener un nombre de propiedad con un espacio, debe usar una expresión JSON.

Por ejemplo

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

Si una consulta NoSQL tiene dos propiedades con el mismo nombre, use alias para cambiar el nombre de una o ambas propiedades para que se desambiguan en el resultado proyectado.

Tenga en cuenta estos datos de ejemplo:

[
  {
    "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"
      },
      ...
    ]
  }
]

Nota:

En estos datos de ejemplo y el resultado de la consulta, se quitaron varias propiedades y valores para mayor brevedad.

Esta consulta NoSQL devuelve las p.sizes[].key propiedades y p.tags[].key en el resultado entre productos, pero aliasá cada key propiedad para evitar colisiones:

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