modify nested object but maintain the full object after - jq

I need to modify an element --an array-- (e.g.: "group-xyz") within a nested object in a JSON tree using JQ but once that's done then I need the entire object back with the modified data.
The goal is to update a JSON tree and save it in full.
e.g.: add array element, empty array, etc.
{
"group-abc": {"users": ["tina.turner"]},
"group-def": {"users": ["someone.else"]},
"group-xyz": {"users": ["that.thing"]
}
Then I am interested in returning an object like this:
{
"group-abc": {"users": ["tina.turner"]},
"group-def": {"users": []},
"group-xyz": {"users": ["that.thing","well.done"]
}

I have changed my requirements to fit a more complex form. To add a user to any of these groups' users this is what I did:
jq '. |= map( if ( .group=="abc") then .users+=["final.answer",] else . end)' source.json
which produced a result
[
{
"group": "abc",
"users": [
"user1",
"user2",
"final.answer"
]
},
{
"group": "def",
"users": [
"user4",
"user5"
]
}
]

Related

JsonPath For multiple object

I want to know the name who purchased items "abc" and "def" from the bellow json data.
(Expected result is "tom")
Please tell me how to do using JsonPath.
[
{
"name": "tom",
"purchased": [
{
"name": "abc"
},
{
"name": "def"
}
]
},
{
"name": "bob",
"purchased": [
{
"name": "xyz"
}
]
}
]
If you are doing this in Java you could select the name of the buyer like this:
$..[?(#.purchased && #..name contains 'abc' && #..name contains 'def' )].name
In JavaScript, you can use this a query like this:
$.[?(#.purchased && #.purchased.some(e => e.name==='abc') && #.purchased.some(e => e.name==='def') )].name
Both queries use a similar approach:
We filter for a purchased-property, then use a function to search the keys in the map for certain values
Jayway's JsonPath offers a contains function to do so;
In JavaScript we leverage script evaluation to search the map/dict for our key/values
So, the .some() is not a JsonPath function but some modern JavaScript (:D).
This is kind of a workaround in both cases but it gets the job done.
You can test both online here. Select the tab JayWay and click Go for the first query, switch to tab Goessner to run the JavaScript sample (you can run the second here as well).

Remove objects from array that match a test against a property

I'd like to remove from an array objects that pass a test against a property'
Assume we have the following array:
[
{
"path": "a/b/v1-another"
},
{
"path": "a/b/v1"
}
]
I'd like to remove from the array the object that match the test a/b/* against path property
Like this:
jq '.[]|select(.path|startswith("a/b/")|not)' file.json

Complex object in a query string

How can I have this structure in a query string?
"properties": {
"list": [
{
"label": "bye",
"value": "world"
},
{
"label": "hello",
"value": "mars"
}
]
}
I've tried it with properties[][list][label]=bye&properties[][list][value]=world&properties[0][label]=hello&properties[0][value]=mars and also with properties[][list][label]=bye&properties[][list][value]=world&properties[][list][label]=hello&properties[][list][value]=mars, none of them worked. I built them in php with http_build_query.
I need to have this structure in a query string because I have to send the data along with some other stuff with POST to a PHP site.
I see two errors in your query string:
properties is an object, so there's no need to use [] to add elements.
list is an array, so you must use numeric indexes in the query string.
The correct query string is:
?properties[list][0][label]=bye
&properties[list][0][value]=world
&properties[list][1][label]=hello
&properties[list][1][value]=mars
(multi-lined for readability)

Firebase data structure - Keeping duplicated data up-to-date

I created a flatted data structure. When pushing duplicated data whats the accepted pattern for keeping that data up-to-date. Here the data for the groups info is duplicated into the users-groups and the groups tree.
{
"users": ..
"users-groups": ..
"groups": ..
}
When creating a group for a user two updates takes place:
First: push to /groups/group_key
{
"name": "Test Group",
"image: "/testimage.jpg"
}
Second: push to /users-groups/user_uid/group_key
{
"orderNum: 0,
"info": {
"name": "Test Group",
"image: "/testimage.jpg"
}
}
Should keeping this data in the user-groups up-to-date be a job for the client or should a server handle this?
The data in the groups tree will always be the newest and the changes should propagate down to all the users that are members of that group.
Is there any tutorials or reference material for this problem?
note: i'm using this structure because a user can be a member of multiple groups and I don't think it would be a good idea to make possibly several ref.once's to get the data from the /groups/ directly.
You can use multi path update. Just observe reference with function and update all other informations
db.ref("").update({
'/users/dedd': info,
'/users/cdcd': info2
})
You should not have data saved duplicated. Instead you should save reference to group.
Your data should look like this.
{
"users": {
"userkey1": {
"data": {
"name": "",
"firstname": ""
},
"groups": {
"groupkey1": true // true or orderNum value
}
}
},
"groups": {
"groupkey1": {
"data": {
"name": "Test Group",
"image": "/testimage.jpg",
"other": "data"
},
"users": {
"userkey1": true
}
}
}
}
You can easily check if user is in group by checking if value at any of these positions is true.
users/userkey1/groups/groupkey1 or groups/groupkey1/users/userkey1.
When you create new group you save in under groups/newgroupkey position and you updated groups under users node by only setting newgroupkey to true.
So you do not duplicate your data.
For more information about structuring your data check the following link.
https://firebase.google.com/docs/database/android/structure-data

How do I query Arrays in Usergrid collections?

I'm successfully able to GET data from
GET /mycollection?ql=select data.visitor.badges where data.visitor._id = 'f33498'
Which returns
{
"action": "get",
"application": "313hhlkhj77080",
"params": {
"ql": [
"select data.visitor.badges where data.visitor._id = 'f33498'"
]
},
"path": "/mycollection",
"uri": "http://xxxx/appservices/xxxxxx/mycollection",
"list": [
[
[
"New Visitor",
"Cart Abandoner"
]
],
[
[
"New Visitor",
"Repeat Visitors",
"Cart Abandoner"
]
],
[
[
"New Visitor",
"Repeat Visitors",
"Browse Abandoner"
]
]
],
"timestamp": 1407968065207,
"duration": 35,
"organization": "visitor-baas",
"applicationName": "sandbox",
"count": 3
}
However, I cannot figure out how to modify the following query to allow me to narrow the result set to only those containing a "Cart Abandoner" value in the data.user.badges array.
Is this possible? I've tried:
GET /mycollection?ql=select data.visitor.badges where data.visitor.badges = 'Cart Abandoner'
This appears to return data.visitor.badges arrays where 'Cart Abandoner' is the last position of the array.
GET /mycollection?ql=select data.visitor.badges where data.visitor.badges contains 'Cart Abandoner'
This appears to return nothing.
What am I missing?
Unfortunately there's currently no way to query arrays. Your best option is to store it as an object instead.
Couple things: I query elements of arrays all the time, but the ql query string is a little temperamental. element = 'string' should return the entire JSON payload if the 'string' is contained anywhere in the array 'element' so the fact you're getting mixed results may be due to the complexity of your nested arrays.
That said, The ql query string allows you to restrict the resources that get returned (like your first example where id = 'xxx'). There isn't any way to return anything other than the entire JSON payload from that resource (such as truncating your array based on the query restriction).
So, if what you're trying to do is pull just the times that your customer returned, I would suggest creating a separate resource called something like "visitorbadges" and connect it to the user record. So instead of querying with the id and trying t query the array you'd have something like:
https://api.usergird.org/{yourorg}/{yourapp}/users/{userid}/vistorbadges
If you use the BaaS userid rather than your own you can go to /users/uuid or, you could also store the userid with the label 'name' ({"name" : "f33498"}) which will let you go to /users/f33498/visitorbadges
See the Apige docs for how to connect resources:
http://apigee.com/docs/app-services/content/connecting-users-other-data

Resources