Kom igång med JSON – Frågespråk i Cosmos DB (i Azure och Fabric)

Att arbeta med JavaScript Object Notation (JSON) är kärnan i frågespråket. Objekt lagras som JSON och alla frågor, uttryck och typer är utformade för att fungera med JSON-data. Mer information om själva JSON finns i den formella JSON-specifikationen.

Här följer några viktiga saker att veta om JSON i den här kontexten:

  • JSON-objekt börjar alltid med { och slutar med }.
  • Egenskaper kan kapslas i varandra.
  • Egenskapsvärden kan vara matriser.
  • Egenskapsnamn är skiftlägeskänsliga.
  • Egenskapsnamn kan vara valfri sträng, även med blanksteg eller specialtecken.

Kapslade egenskaper

Du kan komma åt kapslade JSON-egenskaper med hjälp av punkt notation. Detta fungerar precis som att komma åt egenskaper i de flesta programmeringsspråk.

Här är ett exempeldokument med kapslad 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"
    }
  }
]

Du kan sedan projicera samma kapslade egenskaper i dina frågor:

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

Och du skulle få dessa förväntade utdata:

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

Matriser och uppsättningar

JSON stöder matriser och du kan arbeta med dem i dina frågor. Om du vill komma åt ett visst element använder du dess position i matrisen.

Med samma exempel från föregående avsnitt kan vi komma åt ett objekt i matrisen med hjälp av dess index. Om vi till exempel vill komma åt det första objektet i matrisen använder vi ett index för 0 eftersom det är ett nollbaserat indexsystem för matriser på frågespråket:

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

Den här frågan resulterar i följande JSON-objekt:

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

Nu ska vi överväga ett exempel med en större matris:

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

Ofta vill du använda en underfråga eller en självkoppling för att arbeta med alla element i en matris. Om du till exempel vill hämta varje färg som en separat rad:

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

Vilket skulle resultera i en JSON-matris som den här:

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

Om du vill kontrollera om det finns ett visst värde i en matris kan du använda matrisen i filtret efter nyckelordet WHERE . I det här exemplet används en underfråga för att filtrera matrisens objekt:

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

Den här frågan resulterar i en platt JSON-matris med strängar, som innehåller objektet i exemplet:

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

Slutligen kan du skapa matriser genom att kombinera flera egenskaper. I det här exemplet kombineras flera egenskaper för att bilda en metadata matris:

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

Frågespråket stöder iteration över JSON-matriser med hjälp av nyckelordet INFROM i källan.

Överväg den här exempeldatauppsättningen:

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

Det första exemplet använder nyckelordet IN för att utföra iteration över colors egenskapen för varje produkt:

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

Du kan också filtrera enskilda poster i matrisen med hjälp av WHERE -satsen. I det här exemplet filtreras egenskapen sizes :

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

Med samma IN nyckelord kan du aggregera över resultatet av en matris-iteration. I det här exemplet returnerar frågan antalet taggar som summerats för alla objekt i containern:

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

Anmärkning

När du använder nyckelordet IN för iteration kan du inte filtrera eller projicera några egenskaper utanför matrisen. I stället använder du självkopplingar.

Null- och odefinierade värden

Om en egenskap inte finns i ett dokument är undefineddess värde . Om en egenskap finns men är inställd på nullär det ett explicit angivet värde. Skillnaden mellan null och undefined är en viktig skillnad som kan orsaka förvirring i frågor.

Det här JSON-objektet skulle till exempel ha värdet undefined för egenskapen sku eftersom egenskapen aldrig definierades:

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

Det här JSON-objektet skulle ha värdet null för för samma egenskap eftersom egenskapen har definierats men inte har angetts med ett värde:

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

Det finns inbyggda funktioner för att söka efter följande fall:

  • IS_NULL kontrollerar om en egenskap är null.
  • IS_DEFINED kontrollerar om en egenskap finns (är inte undefined).

Så här kan du söka efter båda:

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

Notation för hakparentes

De flesta exempel använder punkt notation för att ange egenskaper, men du kan alltid ange samma egenskaper med hjälp av hakparentes notation.

Vi börjar med ett enkelt objekt med ett kapslat objekt som värdet för metadata egenskapen:

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

För det objektet kan vi referera till metadata.link egenskapen på tre olika sätt med hjälp av kombinationer av punkt - och hakparenteser :

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

Tips/Råd

Om ett egenskapsnamn har blanksteg, specialtecken eller matchar ett reserverat ord måste du använda hakparentes notation för att ange egenskapen.

JSON-uttryck

Du kan skapa JSON-objekt direkt i frågeresultatet. Vi börjar med den här JSON-matrisen som exempel:

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

Med den enklaste syntaxen kan du påverka egenskapsnamnen för ett relativt platt JSON-objekt med hjälp av vinkelparenteser ({/}) och den inbäddade JSON-syntaxen i en NoSQL-fråga:

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

I föregående exempel hade resultatet ett härledt namn $1 på eftersom ett explicit namn inte definierades. I nästa exempel har resultatet ett explicit namn som definierats med hjälp av product ett 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"
    }
  }
]

Alternativt kan resultatet plattas ut med nyckelordet VALUE i en SELECT VALUE instruktion:

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

Om du går ännu längre kan du använda JSON-syntaxen för att "omforma" JSON-resultatet till att inkludera matriser, underobjekt och andra JSON-konstruktioner som kanske inte uttryckligen definieras i det ursprungliga objektet. Den här tekniken är användbar om klientprogrammet förväntar sig data i ett specifikt schema som inte matchar underliggande data.

Tänk på det här JSON-schemat, till exempel:

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

Det schemat skulle tillåta ett JSON-objekt som är strukturerat i det här formatet:

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

Den här NoSQL-frågan mappar om det ursprungliga objektet för att vara kompatibelt med det här nya schemat:

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

Containeralias

Som standard refererar termen som används efter nyckelordet FROM till den container som är målet för frågan. Själva termen krävs INTE för att matcha namnet på containern.

Om containern till exempel heter productsfungerar någon av dessa frågor bra och alla refererar till containern products så länge containern är målet för frågan:

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

Om du vill göra NoSQL-frågan mer kortfattad är det vanligt att aliaset containernamnet med ett kortare namn. Alias kan utföras med hjälp av nyckelordet AS :

SELECT
  p.id
FROM
  products AS p

Frågespråket har också en kortfattad syntax där aliaset kan definieras omedelbart efter målcontainerns referens utan nyckelordet AS . Den här förkortningen är funktionellt likvärdig med att använda nyckelordet AS :

SELECT
  p.id
FROM
  products p

Egenskapsalias

Du kan också byta namn på fält i dina resultat med hjälp av alias som definieras med samma AS nyckelord. För de kommande exemplen bör du överväga dessa exempeldata:

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

I det första exemplet används aliaset metadataLink för egenskapens metadata.link värde:

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

Viktigt!

Du kan inte använda alias för att projicera ett värde som ett egenskapsnamn med blanksteg, specialtecken eller reserverat ord. Om du vill ändra ett värdeprojektion till att till exempel ha ett egenskapsnamn med ett blanksteg måste du använda ett JSON-uttryck.

Ett exempel:

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

Om en NoSQL-fråga har två egenskaper med samma namn använder du alias för att byta namn på en eller båda egenskaperna så att de är tvetydiga i det beräknade resultatet.

Tänk på dessa exempeldata:

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

Anmärkning

I dessa exempeldata och frågeresultatet togs flera egenskaper och värden bort för korthet.

Den här NoSQL-frågan returnerar p.sizes[].key egenskaperna och p.tags[].key i resultatet mellan produkter, men alias för varje key egenskap för att undvika kollisioner:

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