次の方法で共有


JSON の概要 - Cosmos DB のクエリ言語 (Azure と Fabric)

JavaScript Object Notation (JSON) の操作は、クエリ言語の中核です。 項目は JSON として格納され、すべてのクエリ、式、および型は JSON データを操作するように設計されています。 JSON 自体の詳細については、 正式な JSON 仕様を参照してください。

このコンテキストで JSON について知っておくべき重要な点を次に示します。

  • JSON オブジェクトは常に { で始まり、 }で終わる。
  • プロパティは、相互 に入れ子にすることができます
  • プロパティ値には配列を指定できます。
  • プロパティ名は大文字と小文字が区別されます。
  • プロパティ名には、スペースや特殊文字を含む場合でも、任意の文字列を指定できます。

入れ子になったプロパティ

入れ子になった JSON プロパティには、ドット表記を使用してアクセスできます。 これは、ほとんどのプログラミング言語でプロパティにアクセスするのと同じように機能します。

入れ子になった JSON を含むドキュメントの例を次に示します。

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

その後、クエリに同じ入れ子になったプロパティを射写できます。

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

そして、あなたはこの期待される出力を得るでしょう:

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

配列とセット

JSON は配列をサポートしており、クエリでそれらを操作できます。 特定の要素にアクセスするには、配列内でその位置を使用します。

前のセクションと同じ例を使用して、インデックスを使用して配列内の項目にアクセスできます。 たとえば、配列内の最初の項目にアクセスする場合は、クエリ言語の配列の 0 から始まるインデックス システムであるため、0のインデックスを使用します。

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

このクエリの結果は、次の JSON オブジェクトになります。

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

次に、より大きな配列を持つ例を考えてみましょう。

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

多くの場合、サブクエリまたは自己結合を使用して、配列内のすべての要素を操作します。 たとえば、各色を個別の行として取得するには、次のようにします。

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

これにより、次のような JSON 配列が生成されます。

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

配列に特定の値が存在するかどうかを確認するには、 WHERE キーワードの後のフィルターで配列を使用できます。 この例では、 サブクエリ を使用して配列の項目をフィルター処理します。

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

このクエリの結果、文字列のフラットな JSON 配列が作成されます。この配列には、次の例の項目が含まれます。

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

最後に、複数のプロパティを組み合わせて配列を構築できます。 この例では、複数のプロパティを組み合わせて metadata 配列を形成します。

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

反復

クエリ言語では、FROM ソースの IN キーワードを使用した JSON 配列の反復処理がサポートされています。

次のデータ セットの例を考えてみましょう。

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

この最初の例では、 IN キーワードを使用して、各製品の colors プロパティに対して反復処理を実行します。

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

WHERE句を使用して、配列内の個々のエントリをフィルター処理することもできます。 この例では、 sizes プロパティがフィルター処理されます。

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

同じ IN キーワードを使用して、配列の反復処理の結果を集計できます。 この例では、クエリは、コンテナー内のすべての項目で合計されたタグの数を返します。

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

反復処理に IN キーワードを使用する場合、配列の外部でプロパティをフィルター処理したり投影したりすることはできません。 代わりに、 自己結合を使用します

Null 値と未定義の値

プロパティがドキュメントに存在しない場合、その値は undefined。 プロパティが存在し、 nullに設定されている場合、これは明示的に設定された値です。 nullundefinedの区別は、クエリで混乱を引き起こす可能性のある重要な区別です。

たとえば、この JSON オブジェクトには、プロパティが定義されていないため、sku プロパティの値は undefined になります。

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

この JSON オブジェクトは、プロパティがまだ値で設定されていないため、同じプロパティに対して null の値を持ちます。

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

これらのケースを確認する組み込み関数があります。

  • IS_NULL は、プロパティが nullされているかどうかを確認します。
  • IS_DEFINED は、プロパティが存在するかどうかをチェックします ( undefinedではありません)。

両方を確認する方法を次に示します。

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

角かっこ表記

ほとんどの例では ドット 表記を使用してプロパティを指定しますが、 角かっこ 表記を使用して同じプロパティを常に指定できます。

まず、入れ子になったオブジェクトを metadata プロパティの値として持つ単純なオブジェクトから始めましょう。

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

そのオブジェクトでは、ドット角かっこの表記の組み合わせを使用して、metadata.link プロパティを 3 つの異なる方法で参照できます。

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

ヒント

プロパティ名にスペース、特殊文字、または予約語と一致する場合は、角かっこ表記を使用してプロパティを指定する必要があります。

JSON 式

クエリ結果で JSON オブジェクトを直接作成できます。 例として、次の JSON 配列から始めましょう。

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

最も単純な構文を使用すると、山かっこ ({/}) と NoSQL クエリの埋め込み JSON 構文を使用して、比較的フラットな JSON オブジェクトのプロパティ名に影響を与えることができます。

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

前の例では、明示的な名前が定義されていないため、結果に $1 の推定名がありました。 この次の例では、結果の明示的な名前 product エイリアスを使用して定義されています。

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

または、SELECT VALUE ステートメントで VALUE キーワードを使用して結果をフラット化することもできます。

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

さらに、JSON 構文を使用して結果の JSON オブジェクトを "整形" し、元の項目で明示的に定義されていない可能性がある配列、サブオブジェクト、およびその他の JSON コンストラクトを含めることができます。 この手法は、クライアント アプリケーションが、基になるデータと一致しない特定のスキーマ内のデータを予期している場合に便利です。

次のような JSON スキーマを考えてみましょう。

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

そのスキーマでは、次の形式で構造化された JSON オブジェクトが許可されます。

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

この NoSQL クエリは、元のオブジェクトをこの新しいスキーマに準拠するように再マップします。

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

コンテナーのエイリアス

既定では、 FROM キーワードの後に使用される用語は、クエリのターゲットである コンテナー を参照します。 用語自体は、コンテナーの名前と一致する必要 はありません

たとえば、コンテナーに products という名前が付けられている場合、これらのクエリは正常に動作し、そのコンテナーがクエリのターゲットである限り、products コンテナーを参照します。

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

NoSQL クエリをより簡潔にするために、コンテナー名に短い名前のエイリアスを付けるのが一般的です。 エイリアスは、 AS キーワードを使用して実行できます。

SELECT
  p.id
FROM
  products AS p

クエリ言語には、 AS キーワードを指定せずに、ターゲット コンテナーの参照の直後にエイリアスを定義できる短縮構文もあります。 この短縮形は、 AS キーワードの使用と機能的に同等です。

SELECT
  p.id
FROM
  products p

プロパティのエイリアス

同じ AS キーワードを使用してエイリアス定義を使用して、結果のフィールドの名前を変更することもできます。 次のいくつかの例では、次のサンプル データについて考えてみます。

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

この最初の例では、metadata.link プロパティの値にmetadataLinkエイリアスが使用されます。

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

Important

エイリアスを使用して、スペース、特殊文字、または予約語を含むプロパティ名として値を投影することはできません。 たとえば、スペースを持つプロパティ名を持つ値のプロジェクションを変更する場合は、 JSON 式を使用する必要があります。

たとえば、

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

NoSQL クエリに同じ名前のプロパティが 2 つある場合は、エイリアスを使用してプロパティの一方または両方の名前を変更し、投影された結果であいまいさが解消されるようにします。

次のサンプル データについて考えてみましょう。

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

このサンプル データとクエリ結果では、簡潔にするために複数のプロパティと値が削除されました。

この NoSQL クエリは、クロス積の結果で p.sizes[].key プロパティと p.tags[].key プロパティを返しますが、競合を回避するために各 key プロパティのエイリアスを設定します。

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