Update Embedded Documents in array without Repeating in MongoDb using Java - java

I have the following structure in my document:
{
"_id": 11111,
"user": "user#mail.com",
"sites": [
{
"sitename": "site1",
"url": "site2.com",
"keywords": [],
},
{
"sitename": "site2",
"url": "site2.com",
"keywords": [],
},
{
"sitename": "site2",
"url": "site2.com",
"keywords": [],
},
]
},{
"_id": 2222,
"user": "user2#mail.com",
"sites": []
}
I'm going to find the document by ID(id:11111).there is multiple documents. Then I want to add new site to sites array in the document that contain 1111 _id. if sitename already have, the site should not add. How can I achieve this ?

Updated Answer :
You can check that the _id is '11111', then check that the sitename doesn't exist and is not equal to the new sitename. And then you can $push the embedded document into the array.
db.collection.update(
{
_id:11111,
'sites.sitename' : {$exists:false},
'sites.sitename' : {$ne:'site4'}
},
{
$push:
{
'sites':
{
"sitename": "site4",
"url": "site4.com",
"keywords": []
}
}
},
{
multi:true
}
)

something like
db.collection.update({_id:11111, 'sites.sitename' : {$exists:false}},
{$set : {'sites.$.sitename':'newsite.com'}},{multi:true})
Edit
if you want to add a sub-document for sitename
var sub = {'a':'a','b':'b'};
db.collection.update({_id:11111, 'sites.sitename' : {$exists:false}},
{$set : {'sites.$.sitename':sub}},{multi:true})

Related

Filter nested json data using jsonpath as in example

I am using jsonpath to filter.
Json(Dummy json just to explain) source String, which is basically a list of Operating systems and details of its programs etc. In this example, the OS whose id = 1403 is a windows 10 OS and has 2 features acchritecture and browser. There are more details to the browser feature as shown in json
[
{
"id": 1403,
"os": "window 10",
"features": [
{
"id": 1356,
"name": "architecture",
"value": [
{
"id": 1308,
"feature": [
{
"id": 1262,
"key": "name",
"value": "amd64"
}
]
}
],
"category": "cat1"
},
{
"id": 1357,
"name": "browser",
"value": [
{
"id": 1309,
"feature": [
{
"id": 1263,
"key": "name",
"value": "Firefox"
},
{
"id": 1265,
"key": "version",
"value": "187"
}
]
}
],
"category": "cat2"
}
]
},
{
"id": 2804,
"os": "window 7",
"features": [
{
"id": 2764,
"name": "architecture",
"value": [
{
"id": 2719,
"feature": [
{
"id": 2679,
"key": "name",
"value": "amd64"
}
]
}
],
"category": "cat1"
},
{
"id": 2765,
"name": "browser",
"value": [
{
"id": 2722,
"feature": [
{
"id": 2685,
"key": "name",
"value": "Chrome"
},
{
"id": 2684,
"key": "version",
"value": "87.0.4280.88"
}
]
}
],
"category": "cat2"
}
]
}
]
I want to be able to filter the json such that
features[*].name == 'browser' and features[*].value[*].feature[*].value == 'chrome'
What will be the JsonPath string that can help me achieve above query? The above query uses similar syntax used by JsonPath string but doesn't do the job. Its just to explain.
There is another example here gets Movie Title Given 'Starring' field
And would like to get the full OS json that fulfils this condition. In this case a array of OS which contains only one OS i.e. with id= 2804
[
{
"id": "2804",
...
}
]
I am stuck much before what aim to achieve. Here is my code to get all the OS that have "name=browser". I get the array but it only contains value[] items. I want it get the full json. It returns object with IDs- 1357, 2765.
List<Map<String, Object>> expensive = JsonPath.parse(jsonDataSourceString)
.read("$[*].features[*].[?(#.name == 'browser')]");
To get the outer array you need to use the filter like $[?(...)]
For your current use case, we need to use nested array filters. There is an open issue in JsonPath for filter on children level. (Refer here).
Luckily, there is a workaround suggested to use contains over here.
we can use the below expression to filter:
List<Object> expensive = JsonPath.parse(jsonDataSourceString)
.read("$[?(#.features[?(#.name == 'browser')].value[*].feature[*].value contains 'Chrome')]");
Prints the below output
{id=2804, os=window 7, features=[{"id":2764,"name":"architecture","value":[{"id":2719,"feature":[{"id":2679,"key":"name","value":"amd64"}]}],"category":"cat1"},{"id":2765,"name":"browser","value":[{"id":2722,"feature":[{"id":2685,"key":"name","value":"Chrome"},{"id":2684,"key":"version","value":"87.0.4280.88"}]}],"category":"cat2"}]}

Jolt Transform JSON Spec for Array Input

I am trying to do JOLT shift operation with below spec which is not working. Not sure what mistake I have done. Need help in this case. Output JSON is coming as an object instead of Array and shift also not working as expected.
Input : [
{
"Header": {
"Number": 1,
"Id": "JO"
},
"Name": "John"
},
{
"Header": {
"Number": 2,
"Id": "JS"
},
"Name": "Justin"
}
]
Spec : [
{
"operation": "shift",
"spec": {
"*": {
"Header": "Header",
"Name": "Header.Name"
}
}
}
]
Expected Output : [
{
"Header": {
"Number": 1,
"Id": "JO",
"Name": "John"
}
},
{
"Header": {
"Number": 2,
"Id": "JS",
"Name": "Justin"
}
}
]
Actual Output : {
"Header" : [ {
"Number" : 1,
"Id" : "JO",
"Name" : "John"
}, {
"Number" : 2,
"Id" : "JS"
} ]
}
You have to also specify that the "Header" object is inside the array.
Moreover, the index of the array where you place the "Header" object for each of the element of the array.
That's what the spec below does (using the [&1] - apmersand wildcard combined with array):
[
{
"operation": "shift",
"spec": {
"*": {
"Header": "[&1].Header",
"Name": "[&1].Header.Name"
}
}
}
]
Sources:
Shiftr.java javadocs:
The arrays
The ampersand wildcard
Other answer: "How do I transform an array using Jolt?"
Demo application linked in the jolt repo to test the spec

Jayway JsonPath query to get required json format

I need to extract a json in required format from input json. i'm using jayway json path library. How to achieve it ?
Input Json:
{
"ccid": [
{
"id": 13,
"src": {
"sname": "XA-SXXD",
"lname": "John",
"identifier": 2,
"StatusCode": "C"
}
},
{
"id": 14,
"src": {
"sname": "XB-SXXD",
"lname": "Cena",
"identifier": 3,
"StatusCode": "C",
}
}
]
}
Required Format:
[ {
"id": "13",
"sources": {
"sname": "XA-SXXD",
"lname": "John",
"identifier": 2
}
},
{
"id": "14",
"sources": {
"sname": "XB-SXXD",
"lname": "Cena",
"identifier": 3
}
}]
Query that i use:
$.ccid[*].src[?(#.identifier!=null)].['identifier','sname']
Output that i get:
[
{
"identifier" : 2,
"sname" : "XA-SXXD"
},
{
"identifier" : 3,
"sname" : "XB-SXXD"
}
]
Kindly help me to modify my query to get the required format. The string "sources" in the required format can be hardcoded.
I think I managed to solve this :)
$.ccid[*].[?(#.src.identifier!=null)].['id', 'src']
Give it a try.
Input tested on:
{
"ccid": [
{
"id": 13,
"src": {
"sname": "XA-SXXD",
"lname": "John",
"StatusCode": "C"
}
},
{
"id": 14,
"src": {
"sname": "XB-SXXD",
"lname": "Cena",
"identifier": null,
"StatusCode": "C",
}
}
]
}
Output received:
[
{
"id" : 13,
"src" : {
"sname" : "XA-SXXD",
"lname" : "John",
"StatusCode" : "C"
}
}
]
Only problem is saw is if identifier tag is not available it's essentially treated as not-null. Hence we are getting 13 as an output. But if value is explicitly null then it's fine. So the needs to be enhanced a bit more.
Hope this helps.

tExtractJSONField From tFileInputJSON - Talent Open Studio

I am very new to Talend Open Studio for DI. I am trying to read data from the below JSON File :
{
"data": [
{
"id": "X999_Y999",
"from": {
"name": "Tom Brady", "id": "X12"
},
"message": "Looking forward to 2010!",
"actions": [
{
"name": "Comment",
"link": "http://www.facebook.com/X999/posts/Y999"
},
{
"name": "Like",
"link": "http://www.facebook.com/X999/posts/Y999"
}
],
"type": "status",
"created_time": "2010-08-02T21:27:44+0000",
"updated_time": "2010-08-02T21:27:44+0000"
},
{
"id": "X998_Y998",
"from": {
"name": "Peyton Manning", "id": "X18"
},
"message": "Where's my contract?",
"actions": [
{
"name": "Comment",
"link": "http://www.facebook.com/X998/posts/Y998"
},
{
"name": "Like",
"link": "http://www.facebook.com/X998/posts/Y998"
}
],
"type": "status",
"created_time": "2010-08-02T21:27:44+0000",
"updated_time": "2010-08-02T21:27:44+0000"
}
]
}
I want to load three attributes into my table ( id, actions_name and actions_link). So, in the first step (tFileInputJSON) - I tried to do a Loop Json query as below:
Here, am able to extract the rows as I needed. But, then I used a tExtractJSONField to extract individual fields under "actions" for each "id" using XPath expressions as below:
I tried several other ways to extract the fields but could not do this. Also, not able to find any correct post in stack overflow and talent forums very relevant to my question. Could somebody please help?
Arrange the job like ,
tFileInputJSON is like,
tExtractJSONFields is like,
Then you will get output as,

Selected read JSON by url

I want to make my code as simple as I can and don't want to download items which are not needed.
I want to select only Pages when I'm admin on facebook.
For now I use:
https://graph.facebook.com/v2.0/me/?fields=id,accounts{id,perms}&summary=true&limit=100&access_token=MY_TOKEN
Results:
{
"id": "101506",
"accounts": {
"data": [
{
"id": "6986842335",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
},
{
"id": "1374577066121",
"perms": [
"BASIC_ADMIN"
]
},
{
"id": "997587036984",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
},
],
}
}
Now, how to change the query to read only items with perms=ADMINISTER ?
This is what I need:
{
"id": "101506",
"accounts": {
"data": [
{
"id": "6986842335",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
},
{
"id": "997587036984",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
},
],
}
}
If I can't make the query to read what I need, maybe you know how to do this in Java to check the length of pages?
For now I have:
User = facebookClient.fetchObject("v2.0/me", JsonObject.class, Parameter.with("summary", true), Parameter.with("fields", "id,name,accounts{id,perms}"), Parameter.with("limit", 100));
Integer userFPCount = User.getJsonObject("accounts").getJsonArray("data").length();
But this code gives me results: 3. How to check the length of accounts.data.perms(ADMINISTER) ? I should have result: 2 in this example.
THANK YOU FOR YOUR HELP !

Categories

Resources