How to get the first value of a filtered JSONPath output - jsonpath

Below is the sample json that I used to get data based on string search using JSONPath.
{
"tool":
{
"jsonpath":
{
"creator":
{
"name": "Jayway Inc.",
"location":
[
"Malmo",
"San Francisco",
"Helsingborg"
]
}
}
},
"book":
[
{
"title": "Beginning JSON",
"price": 49.99
},
{
"title": "JSON at Work",
"price": 59.99
}
]
}
The JSONPath expression used is
"$.book[?(#.price == 49.99)].title"
The response for the above JSONPath is an array with single string that is the title.
[
"Beginning JSON"
]
Is it possible to get the output as a String instead of an array. It is ok to get the first value if it contains multiple values in the array.

Related

How to find the parent keys of a jsonpath result

I have this json obj
{
"abc": {
"some_field": {
"title": "Token",
"type": "password"
},
"some_field_2": {
"title": "Domain",
"type": "text"
},
"some_field_3": {
"title": "token2",
"type": "password"
}
}
}
And I want to get a list of keys [some_field,some_field_3] where type=password
This jsonpath $..[?(#.type=='password')] returns:
[
{
"title": "Token",
"type": "password"
},
{
"title": "token2",
"type": "password"
},
]
What should I do?
Thanks.
You are almost there, just need to add a ~ to the end to get the key(s) instead of the value(s):
$..[?(#.type=='password')]~
Note: this might not work depending on your jsonpath engine. It works on https://jsonpath.com.

jq: combine multi array in dict without permutate

are there have any way to achieve simply as expected?
it using combine with permutate in default.
The Following Case
source
{
"title":["title1","title2"],
"link":["http://testapi.cn","http://testapi.org"]
}
expression [{title:.title[],link:.link[]}]
console
[
{
"title": "title1",
"link": "http://testapi.cn"
},
{
"title": "title1",
"link": "http://testapi.org"
},
{
"title": "title2",
"link": "http://testapi.cn"
},
{
"title": "title2",
"link": "http://testapi.org"
}
]
expected
[
{
"title": "title1",
"link": "http://testapi.cn"
},
{
"title": "title2",
"link": "http://testapi.org"
}
]
Use transpose to generate an array of arrays with one element of each input array.
[.title,.link] | transpose | map({title:.[0],link:.[1]})

CosmosDB SQL to query "any" child field

Given a document structure like below, where "variants" has N id based sub-entries, I would like to filter on the inner "sku" field. Something akin to this:
SELECT * FROM c WHERE c.variants.?.sku = "some_sku_1"
Here "some_id_1" and "some_id_2" are id values, data driven, and cannot be part of the query.
Is this possible with Cosmos DB and if so, how?
{
"id": "45144",
"variants": {
"some_id_1": {
"sku": "some_sku_1",
"title": "some title 1"
},
"some_id_2": {
"sku": "some_sku_2",
"title": "some title 2"
}
}
}
You can't do that with that schema without using a UDF/SPROC, but if you change the schema slightly, you can do it.
Schema:
{
"id": "45144",
"variants": [
{
"id": "some_id_1",
"sku": "some_sku_1",
"title": "some title 1"
},
{
"id": "some_id_2"
"sku": "some_sku_2",
"title": "some title 2"
}
]
}
Query:
SELECT * FROM c IN Item.variants WHERE c.sku == "some_sku_1"
Check out this article to get a good idea of what's possible with that "IN' statement, which allows you to iterate over objects. https://learn.microsoft.com/en-us/azure/cosmos-db/sql-api-sql-query#Advanced

QJsonDocument::array() and QJsonDocument::object()

I am reading the QJsonDocument documentation and I use QJsonDocument with following line:
emit this->ueSignalNewDataArrivedPlaces(QJsonDocument::fromBinaryData(incomingData[0].toByteArray()));
and I do not understand, after this line, should I use QJsonDocument::array() or QJsonDocument::object(), i.e., in what situations does QJsonDocument create array and in what situations does create object?
A JSON array is an ordered list, it is written as:
[ <item1>, <item2>, <item3> ]
while a JSON object is a named list, written as:
{
<name1>: <item1>,
<name2>: <item2>
}
In Qt, a QJsonArray is equivalent to a QVariantList (QList<QVariant>) and a QJsonObject is equivalent to QVariantMap (QMap<QString, QVariant>).
Which one you have to use depends on the file you are parsing.
For instance, taking Wikipedia example:
{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
},
{
"type": "mobile",
"number": "123 456-7890"
}
],
"children": [],
"spouse": null
}
You would use a QJsonArray to get the list of phoneNumbers, each element of phoneNumbers is a QJsonObject whith 2 named values: type and number.
If in your code you need to manipulate a JSON element but you do not know its type you can use QJsonValue, which is one of: QJsonObject, QJsonArray, bool, double or a QString

Document Db query filter for an attribute that contains an array

With the sample json shown below, am trying to retrieve all documents that contains atleast one category which is array object wrapped underneath Categories that has the text value 'drinks' with the following query but the returned result is empty. Can someone help me get this right?
SELECT items.id
,items.description
,items.Categories
FROM items
WHERE ARRAY_CONTAINS(items.Categories.Category.Text, "drink")
{
"id": "1dbaf1d0-6549-11a0-88a8-001256957023",
"Categories": {
"Category": [{
"Type": "GS1",
"Id": "10000266",
"Text": "Stimulants/Energy Drinks Ready to Drink"
}, {
"Type": "GS2",
"Id": "10000266",
"Text": "Healthy Drink"
}]
}
},
Note: The json is a bit wierd to have the array wrapped by an object itself - this json was converted from a XML hence the result. So please assume I do not have any control over how this object is saved as json
You need to flatten the document in your query to get the result you want by joining the array back to the main document. The query you want would look like this:
SELECT items.id, items.Categories
FROM items
JOIN Category IN items.Categories.Category
WHERE CONTAINS(LOWER(Category.Text), "drink")
However, because there is no concept of a DISTINCT query, this will produce duplicates equal to the number of Category items that contain the word "drink". So this query would produce your example document twice like this:
[
{
"id": "1dbaf1d0-6549-11a0-88a8-001256957023",
"Categories": {
"Category": [
{
"Type": "GS1",
"Id": "10000266",
"Text": "Stimulants/Energy Drinks Ready to Drink"
},
{
"Type": "GS2",
"Id": "10000266",
"Text": "Healthy Drink"
}
]
}
},
{
"id": "1dbaf1d0-6549-11a0-88a8-001256957023",
"Categories": {
"Category": [
{
"Type": "GS1",
"Id": "10000266",
"Text": "Stimulants/Energy Drinks Ready to Drink"
},
{
"Type": "GS2",
"Id": "10000266",
"Text": "Healthy Drink"
}
]
}
}
]
This could be problematic and expensive if the Categories array holds a lot of Category items that have "drink" in them.
You can cut that down if you are only interested in a single Category by changing the query to:
SELECT items.id, Category
FROM items
JOIN Category IN items.Categories.Category
WHERE CONTAINS(LOWER(Category.Text), "drink")
Which would produce a more concise result with only the id field repeated with each matching Category item showing up once:
[{
"id": "1dbaf1d0-6549-11a0-88a8-001256957023",
"Category": {
"Type": "GS1",
"Id": "10000266",
"Text": "Stimulants/Energy Drinks Ready to Drink"
}
},
{
"id": "1dbaf1d0-6549-11a0-88a8-001256957023",
"Category": {
"Type": "GS2",
"Id": "10000266",
"Text": "Healthy Drink"
}
}]
Otherwise, you will have to filter the results when you get them back from the query to remove duplicate documents.
If it were me and I was building a production system with this requirement, I'd use Azure Search. Here is some info on hooking it up to DocumentDB.
If you don't want to do that and we must live with the constraint that you can't change the shape of the documents, the only way I can think to do this is to use a User Defined Function (UDF) like this:
function GetItemsWithMatchingCategories(categories, matchingString) {
if (Array.isArray(categories) && categories !== null) {
var lowerMatchingString = matchingString.toLowerCase();
for (var index = 0; index < categories.length; index++) {
var category = categories[index];
var categoryName = category.Text.toLowerCase();
if (categoryName.indexOf(lowerMatchingString) >= 0) {
return true;
}
}
}
}
Note, the code above was modified by the asker after actually trying it out so it's somewhat tested.
You would use it with a query like this:
SELECT * FROM items WHERE udf.GetItemsWithMatchingCategories(items.Categories, "drink")
Also, note that this will result in a full table scan (unless you can combine it with other criteria that can use an index) which may or may not meet your performance/RU limit constraints.

Resources