Cosmos Nested JSON Query - azure-cosmosdb

This is the fist time that I work with CosmosDB and I am trying to create a Query to get some details about this JSON:
{
"Status": "Uploaded",
"ProvidedOn": "2022-04-04T18:34:57.4160484Z",
"DocumentTaxonomy": {
"JurisdictionalCountriesOfService": [
{
"Id": 5,
"Name": "United States"
}
],
"WorkProduct": {
"Id": 762,
"Name": "Other reports and documents",
"Type": "Info item"
}
},
"id": "3a92c052-bc23-4b8a-acbf-54044785968a",
"Meta": {
"VersionId": "3",
"LastUpdated": "0001-01-01T00:00:00",
"Source": null,
"Security": null,
"Tag": null,
"Id": null,
"Extension": null,
"ModifierExtension": null
},
}
Basicaly I need to get something like
SELECT id,Status,ProvidedOn, WorkProductName, WorkProductType,MetaVersionId FROM JSONFILE
In this image I am highlighting the columnsthat my query needs
NOTE: since I need to query different CosmoDB, not all of them have the DocumentTaxonomy section so the plan is when they doesn't exists return like a null or blank value

As per your question, the code should return the DocumentTaxonomy section values if they exist in the JSON otherwise It should return null or blank values.
This code may work for you:
SELECT c.id, c.ProvidedOn, c.Status,c.Meta.VersionId as versionId,
IS_DEFINED(c.DocumentTaxonomy.WorkProduct.Type) = true ? c.DocumentTaxonomy.WorkProduct.Type
: IS_DEFINED(c.DocumentTaxonomy.WorkProduct.Type) = false ? null
: "some default value"
as TypeDoc,
IS_DEFINED(c.DocumentTaxonomy.WorkProduct.Name) = true ? c.DocumentTaxonomy.WorkProduct.Name
: IS_DEFINED(c.DocumentTaxonomy.WorkProduct.Name) = false ? null
: "some default value"
as NameDoc
FROM c
The Output it gave when DocumentTaxonomy section exists is:
[
{
"id": "3a92c052-bc23-4b8a-acbf-54044785968a",
"ProvidedOn": "2022-04-04T18:34:57.4160484Z",
"Status": "Uploaded",
"versionId": "3",
"TypeDoc": "Info item",
"NameDoc": "Other reports and documents"
}
]
The Output when DocumentTaxonomy section not exists :
[
{
"id": "3a92c052-bc23-4b8a-acbf-54044785968a",
"ProvidedOn": "2022-04-04T18:34:57.4160484Z",
"Status": "Uploaded",
"versionId": "3",
"TypeDoc": null,
"NameDoc": null
}
]
Please check the screenshot of the output for your reference:

Related

JsonPath: get root element depending on first level sub-element

I need all elements (including "id" and all attributes) of the json sample below where "type" has the value "state_machine_state", but only if "type" is on the first level. I don't want the middle element "order_transaction" in the result, although it has "type": "state_machine_state" in the second hierarchy level.
[
{
"id": "f45aa035eb424d26a0529d25b3647c32",
"type": "state_machine_state",
"attributes": {
"technicalName": "cancelled",
"name": "Cancelled",
"stateMachineId": "7553ad2630044fa589d786135d5000ad",
"customFields": null,
"createdAt": "2020-06-05T14:23:30.503+02:00",
"updatedAt": null,
"translated": {
"name": "Cancelled",
"customFields": []
},
"apiAlias": null
}
},
{
"id": "2d24ed4179824dbe92eee2f3d4f885b1",
"type": "order_transaction",
"relationships": {
"stateMachineState": {
"data": {
"type": "state_machine_state",
"id": "21f236e8955f45d3931fc9e44615088a"
}
}
},
"meta": null
},
{
"id": "d08e73da41b0473d83ea378a57a2fa1f",
"type": "state_machine_state",
"attributes": {
"technicalName": "completed",
"name": "Completed",
"stateMachineId": "7553ad2630044fa589d786135d5000ad",
"customFields": null,
"createdAt": "2020-06-05T14:23:30.482+02:00",
"updatedAt": null,
"translated": {
"name": "Completed",
"customFields": []
},
"apiAlias": null
},
"meta": null
}
]
With the query below I get all three elements
$..[?(#.type == 'state_machine_state')]
I just can't manage to select only the first level elements.
Could anyone please help?
Some implementations will allow you to select several items, but you're not going to be able to get the values with their keys.
For example, if you do
$..[?(#.type == 'state_machine_state')['id','attributes']
You'll just get a result set that contains all of the id values and all of the attributes values.
[
"f45aa035eb424d26a0529d25b3647c32",
{
"technicalName": "cancelled",
"name": "Cancelled",
"stateMachineId": "7553ad2630044fa589d786135d5000ad",
"customFields": null,
"createdAt": "2020-06-05T14:23:30.503+02:00",
"updatedAt": null,
"translated": {
"name": "Cancelled",
"customFields": []
},
"apiAlias": null
},
"2d24ed4179824dbe92eee2f3d4f885b1",
"d08e73da41b0473d83ea378a57a2fa1f",
{
"technicalName": "completed",
"name": "Completed",
"stateMachineId": "7553ad2630044fa589d786135d5000ad",
"customFields": null,
"createdAt": "2020-06-05T14:23:30.482+02:00",
"updatedAt": null,
"translated": {
"name": "Completed",
"customFields": []
},
"apiAlias": null
}
]
JSON Path isn't designed for transformation. JMES Path might be able to do what you're looking for, but I'm not as familiar with it.
Sometimes it helps to take a step back and think another way.
With this query I get exactly what I want:
$..[?(#.type == 'state_machine_state' && #.attributes)]
The elements I need have attributes, the others don't, so I just check for that in the filter.

Conditional select using jq

I have this below json format, I want to take the list of "id" which satisfies the condition
in this below I want to take the id which has matchers.value as dev-stack and status.state as active
{
"status": "success",
"data": [
{
"id": "b5e7f85d",
"matchers": [
{
"name": "stack",
"value": "dev-stack",
"isRegex": true
}
],
"startsAt": "2020-07-13T07:17:36Z",
"endsAt": "2020-07-15T07:15:44Z",
"updatedAt": "2020-07-13T07:15:59.643692023Z",
"createdBy": "api",
"comment": "Silence",
"status": {
"state": "active"
}
},
{
"id": "1fdaa4b5",
"matchers": [
{
"name": "stack",
"value": "qa-stack",
"isRegex": true
}
],
"startsAt": "2020-07-10T13:19:12Z",
"endsAt": "2020-07-10T13:20:55.510739499Z",
"updatedAt": "2020-07-10T13:20:55.510739499Z",
"createdBy": "api",
"comment": "Silence",
"status": {
"state": "expired"
}
}
]
}
Here is a solution which uses update assignment |=, map and select to update .data.
Note it avoids an undesirable cartesian product if multiple .matchers meet the criteria by using any.
.data |= map(select(
(.matchers | any(.value=="dev-stack")) and (.status.state=="active")
))
Try it online!

DocumentDB: How to Update Partial Property Value

I have been struggling with this for a while. Here is my Document.
{
"id": "1",
"Scenario": "Welcome page",
"Translations": [
{
"Language": "En",
"Content": "Welcome!"
},
{
"Language": "Fr",
"Content": "Bienvenue!"
}
],
"LastModified": "2016-05-27T17:27:58.562-06:00",
"ModifiedBy": "admin",
"LastAccessed": "2016-06-13T10:27:58.562-06:00"
}
And here is my code to update the property (I've hard-coded the value to be modified here):
SqlQuerySpec query = new SqlQuerySpec()
{
QueryText = "SELECT c.id, c.Scenario, t.Language, t.Content, c.LastModified, c.ModifiedBy, c.LastAccessed FROM MultiLanguage as c join t in c.Translations where c.id = #Id and t.Language = #Language",
Parameters = new SqlParameterCollection() { new SqlParameter("#Id", Id), new SqlParameter("#Language", Language) }
};
Document doc = client.CreateDocumentQuery<Document>(
collectionLink, query).AsEnumerable().FirstOrDefault();
doc.SetPropertyValue("Content", "Welcome to Stackoverflow!");
Document updated = await client.ReplaceDocumentAsync(doc);
There are two parameters passed into this function. Id and Language. For example, I only want to update the property Content to "Welcome to Stackoverflow!" for Id = "1" and Language="En". The thing is my code will remove the other "Language": "Fr", "Content": "Bienvenue!" part and update my document to something like this:
{
"id": "1",
"Scenario": "Welcome page",
"Language": "En",
"Content": "Welcome to Stackoverflow!",
"LastModified": "2016-05-27T17:27:58.562-06:00",
"ModifiedBy": "admin",
"LastAccessed": "2016-06-13T10:27:58.562-06:00"
}
But what I want is this:
{
"id": "1",
"Scenario": "Welcome page",
"Translations": [
{
"Language": "En",
"Content": "Welcome to Stackoverflow!"
},
{
"Language": "Fr",
"Content": "Bienvenue!"
}
],
"LastModified": "2016-05-27T17:27:58.562-06:00",
"ModifiedBy": "admin",
"LastAccessed": "2016-06-13T10:27:58.562-06:00"
}
So how can I only update partial property of the document without messing up other properties?
DocumentDB has no update in place. You have to read the doc, update it client side, and then re-save it over the top of the old one. Alternatively, you could denormalize your list of translations into separate documents with "foreign keys" back to the Scenario it relates to.

How do I update a non-unique property in Freebase?

I've been working on a calorie counter and I'm slowly making progress on my MQL write. The issue that I'm having currently is updating the recipe itself which is in the /common/topic/description property.
The query that I am using currently is:
[{
id: recipeId, // previously retrieved
'/common/topic/description': {
connect: 'replace',
value: $('#description textarea').val(),
lang: '/lang/en'
}
}]
This succeeds in executing, but when I query (another) after it has run I get an error:
{
"domain": "global",
"reason": "invalid",
"message": "Unique query may have at most one result. Got 2",
"locationType": "other",
"location": "/common/topic/description"
}
According to the documentation, connect: replace does an update on unique properties and an insert on non-unique ones. So am I getting that because a value was inserted?
Is it necessary to remove the other value to prevent the error? Do I need to know the existing value in order to remove it?
{
id: recipeId,
'/common/topic/description': {
connect: 'delete',
value: 'Value currently stored',
lang: '/lang/en'
}
}
The problem doesn't anything to do with updating non-unique properties. Your read query is the issue. You didn't quote the failing query, but the part of the error message that says "location": "/common/topic/description" is your hint. That topic has two descriptions, one empty and one not, but you haven't used array notation in you query.
This will work:
[{
"id": "/m/0wh83sg",
"/food/recipe/ingredients": [{
"id": null,
"ingredient": {
"id": null,
"name": null,
"/food/food/energy": null,
"/common/topic/image": {
"id": null,
"optional": true,
"limit": 1
},
"optional": true
},
"unit": {
"id": null,
"name": null,
"optional": true
},
"quantity": null,
"notes": null
}],
"/common/topic/description": [{}]
}]

Related information about location in freebase are always null?

I'm trying to query freebase to find information about a specific city.
I'm able to find the city that I'm looking for but I need to get the description content as well as a few pictures.
My current query is
[{
"name": "san francisco",
"id": null,
"type": "/location/citytown",
"/location/location/geolocation" : [
{
"latitude": null,
"longitude": null,
"latitude>" : 36,
"latitude<" : 38 }]
"/common/topic/article" : [{ "id" : null, "content": null }],
"/common/topic/image" : [{
"id" : null,
"optional" : true,
"limit" : 15
"image_caption" : []
}]
}]
Which returns
{
"code": "/api/status/ok",
"result": [{
"/common/topic/article": [{
"content": null,
"id": "/m/0d6l_"
}],
"/common/topic/image": [
{
"id": "/m/02929wx",
"image_caption": []
},
{
"id": "/m/04j74y4",
"image_caption": []
},
{
"id": "/m/04j74yh",
"image_caption": []
},
{
"id": "/m/04j74yw",
"image_caption": []
},
{
"id": "/m/04j74z6",
"image_caption": []
}
],
"/location/location/geolocation": [{
"latitude": 37.775,
"longitude": -122.4183
}],
"id": "/en/san_francisco",
"name": "San Francisco",
"type": "/location/citytown"
}],
"status": "200 OK",
"transaction_id": "cache;cache03.p01.sjc1:8101;2012-07-24T21:50:06Z;0029"
}
I can't get the content value and the captions to be set.
Am I missing something ?
Where did you find the "image_caption" property? If you switch it to "name" you should get the names of the images (which are used as captions in some UI contexts).
The text content isn't available from MQL, but you can get it from the BLOB service in the old API or the text API in the new APIs using the ID that is returned for the article. e.g. https://www.googleapis.com/freebase/v1/text/m/0d6l_
p.s. If you just want the primary image, you might consider using the Topic API which will return you the image, it's name, the text blurb, and a bunch of other info in a single call.
https://www.googleapis.com/freebase/v1/topic/wikipedia/en_id/49728
Using the Search API will give you more robust name matching as well as give you a score which will tell you how likely it is that the query is ambiguous (if you get multiple matches with scores close to each other).
https://www.googleapis.com/freebase/v1/search?query=%22san%20francisco%22&type=/location/citytown

Resources