how to delete an element from json file using xquery - xquery

I have a .json file in MarkLogic as :
{
"contextProductIdCDM": {
"variables": {
"source": "'Inm'",
"source_table_id": "'123'",
"Referdate": "normalize-space(string-join((J_MCCC, if(J_MCDC eq '') then '000' else J_MCDC),''))"
},
"$ref": "#/contexts/Closure"
},
"predcondition": "xyz=1"
}
I want to delete the predcondition and also want to delete some part of referdata also using xquery. Can anyone help how to achieve that?

If you wanted to remove the precondition field and modify the contextProductIdCDM.variables.Referdate value, you could address those JSON properties with XPath and use xdmp:node-delete() and xdmp:node-replace() functions:
xquery version "1.0-ml";
let $doc := fn:doc("/test.json")
return (
xdmp:node-replace($doc/contextProductIdCDM/variables/Referdate, text{ "000" }),
xdmp:node-delete($doc/predcondition)
)
How it could be done in JavaScript; convert to a plain old object, make the modifications, then replace the document with that updated JSON object:
declareUpdate();
const doc = cts.doc("/test.json");
let obj = doc.toObject(); // create mutable representation
obj.contextProductIdCDM.variables.Referdate = '000'; //change the Referdate property value
delete obj.predcondition; // delete precondition field
xdmp.nodeReplace(doc, obj); // update the JSON document with the changes

Related

Searching a DynamoDB String Set Attribute by Array of Strings

I am struggling to find the correct syntax to search a String Set/List target attribute (tags) by an array of strings. The idea would be that if the SS attribute contains all of the passed strings, it passes the filter. The passed strings do not need to match all of the strings within the target attribute. The more strings you pass, the more accurate your results.
// Compile tags into a list
let tagSqlValues = {};
let tagSqlStatement = query.tags.map((tag: string, index: number) => {
let tagParam = `:tag${index}`;
tagSqlValues[tagParam] = tag;
return `${tagParam} in tags`;
}).join(" and ");
// Console Logs
// tagSqlStatement = :tag0 in tags and :tag1 in tags (also tried tags contains :tag0 and tags contains :tag1)
// tagSqlValues = {":tag0":"Modern",":tag1":" Spring"}
let params = {
TableName: "Art",
FilterExpression: tagSqlStatement,
ExpressionAttributeValues: tagSqlValues,
};
let results = await this.DDB_CLIENT.scan(params).promise();
// Console Logs
// "Invalid FilterExpression: Syntax error; token: \"tags\", near: \"in tags and\""
// "Invalid FilterExpression: Syntax error; token: \"contains\", near: \"tags contains :tag0\""
I've tried several variations with IN and CONTAINS without luck. Is this possible with DynamoDB?
It looks like my CONTAINS syntax was wrong. I did a little digging and found this answer by Zanon. With a minor modification to include the and join, it seems like the filter is working as expected!
// Compile tags into a list
let tagSqlValues = {};
let tagSqlStatement = query.tags.map((tag: string, index: number) => {
let tagParam = `:tag${index}`;
tagSqlValues[tagParam] = tag;
return `contains(tags, ${tagParam})`;
}).join(" and ");

DynamoDB update - "ValidationException: An operand in the update expression has an incorrect data type"

I am trying to append to a string set (array of strings) column, which may or may not already exist, in a DynamoDB table. I referred to SO questions like this and this when writing my UpdateExpression.
My code looks like this.
const AWS = require('aws-sdk')
const dynamo = new AWS.DynamoDB.DocumentClient()
const updateParams = {
// The table definitely exists.
TableName: process.env.DYNAMO_TABLE_NAME,
Key: {
email: user.email
},
// The column may or may not exist, which is why I am combining list_append with if_not_exists.
UpdateExpression: 'SET #column = list_append(if_not_exists(#column, :empty_list), :vals)',
ExpressionAttributeNames: {
'#column': 'items'
},
ExpressionAttributeValues: {
':vals': ['test', 'test2'],
':empty_list': []
},
ReturnValues: 'UPDATED_NEW'
}
dynamo.update(updateParams).promise().catch((error) => {
console.log(`Error: ${error}`)
})
However, I am getting this error: ValidationException: An operand in the update expression has an incorrect data type. What am I doing incorrectly here?
[Update]
Thanks to Nadav Har'El's answer, I was able to make it work by amending the params to use the ADD operation instead of SET.
const updateParams = {
TableName: process.env.DYNAMO_TABLE_NAME,
Key: {
email: user.email
},
UpdateExpression: 'ADD items :vals',
ExpressionAttributeValues: {
':vals': dynamo.createSet(['test', 'test2'])
}
}
A list and a string set are not the same type - a string set can only hold strings while a list may hold any types (including nested lists and objects), element types don't need to be the same, and a list can hold also duplicate items. So if your original item is indeed as you said a string set, not a list, this explains why this operation cannot work.
To add items to a string set, use the ADD operation, not the SET operation. The parameter you will give to add should be a set (not a list, I don't know the magic js syntax to specify this, check your docs) with a bunch of elements. If the attribute already exists these elements will be added to it (dropping duplicates), and if the attribute doesn't already exit, it will be set to the set of these elements. See the documentation here: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html#DDB-UpdateItem-request-UpdateExpression

How to select an element which has () in it using JSON

I am using RestAssured for API automation and as a part of it I have to extract a value from the JSON reponse.
JSON reponse is given below
{
"resourceName": "SERVICE_STATUS",
"records": [
{
"CREATED_DTTM": "2019-08-12T05:58:12.940Z",
"STATUS": "SUCCESS",
"SERVICE_EXECUTION_ID": "e760bed8-2ebb-4563-9812-7c0e5ed565cf",
"OUTPUT_FILE(S)": [
"FileC_FileA.csv"
],
"SERVICE_ID": "EXCEL2CSV"
}
],
"status": "SUCCESS"
}
I have to extract the value "FileC_FileA.csv" from the response, but when i do it via Json Path it is failing as "()" has special meaning in json path.
JsonPath js1 = new JsonPath(statusrespstring);
String outputfile = js1.get("OUTPUT_FILE(S)"); -----> This is failing
I have tried using
String outputfile = js1.get("OUTPUT_FILE"+"("+"S"+")");
String outputfile = js1.get('OUTPUT_FILE(S)');
But getting error as
: The parameter "S" was used but not defined. Define parameters using the JsonPath.params(...) function
Someone please help, how to select a value whose key parameter has () in it.
I have found the solution.
ArrayList<String> outputfile = js1.get("records[0].'OUTPUT_FILE(S)'");
If the property has special character then surrounding with single quotes will work.
Reference : https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html

Cloud Functions for Firebase: write to database on fileupload

I have a cloud function (modified version of generateThumbnail sample function). I want to create thumbnail, but I also want to get image width and height, and update size value in the database.
To break up this problem:
I need to get snapshot of current database
Navigate to /projects of database
Find correct key using filename (project.src == fileName)
Get size of image (done)
Update project.size to new value
I did some research, but I only found the functions.database.DeltaSnapshot interface, that is given, when you listen on functions.database().ref().onwrite(snapshot => {})
projects.json:
[{
"name": "lolipop",
"src": "lolipop.jpg",
"size": ""
},{
"name": "cookie",
"src": "cookie.jpg",
"size": ""
}]
Database interaction can be done using the firebase-admin package. Check out this sample to see how a function not triggered by a database write accesses the database.
Accessing child nodes by the value of one of their keys in Firebase is a bit clunky, more on that at the end.
For each concern:
1 & 2: create a reference to the projects key in your DB
3: Find the project you're looking for by its src key
5: Update the project
// create reference
const projectsRef = admin.database().ref('projects');
// create query
const srcProjectQuery = projectsRef.orderByChild('src').equalTo(fileName);
// read objects that fit the query
return srcPojectQuery.once('value').then(snapshot => {
const updates = {};
snapshot.forEach(childSnapshot => {
updates[`${childSnapshot.key}/size`] = fileSize;
});
return projectsRef.update(updates);
});
Since it looks like you're treating the src values as unique, a lot of headache can be avoided by using the src as the key for each project object. This would simplify things to:
const projectsRef = admin.database().ref(`projects/${src}`);
projectsRef.update({'size': fileSize});

filter the Json according to string in an array in JSONPATH

I have a situation where I have json String that has a child as Array that contains only Strings. Is there as way I can get the object reference of the arrays that contains a specific String.
Example:
{ "Books":{
"History":[
{
"badge":"y",
"Tags":[
"Indian","Culture"
],
"ISBN":"xxxxxxx",
"id":1,
"name":"Cultures in India"
},
{
"badge":"y",
"Tags":[
"Pre-historic","Creatures"
],
"ISBN":"xxxxxxx",
"id":1,
"name":"Pre-historic Ages"
}
]
}
}
To Achieve:
From the above JSON String, need to get all books in History which contains "Indian" inside the "tags" list.
I am using JSONPATH in my project but If there is other API that can provide similar functionality, any help is welcome.
If you're using Goessner JSONPath, $.Books.History[?(#.Tags.indexOf('Indian') != -1)] as mentioned by Duncan above should work.
If you're using the Jayway Java port (github.com/jayway/JsonPath), then
$.Books.History[?(#.Tags[?(# == 'Indian')] != [])] or more elegantly, use the in operator like this $.Books.History[?('Indian' in #.Tags)]. Tried them both here.
Assuming you are using Goessner JSONPath (http://goessner.net/articles/JsonPath/) the following should work:
$.Books.History[?(#.Tags.indexOf('Indian') != -1)]
According to the Goessner site, you can use underlying JavaScript inside the ?() filter. You can therefore use the JavaScript indexOf function to check if your Tags array contains the tag 'Indian'.
See a working example here using this JSONPath query tester:
http://www.jsonquerytool.com/sample/jsonpathfilterbyarraycontents
Did you try to use underscoreJS ? You can get the Indian books like this :
var data = {"Books:"....};
var indianBooks = _.filter(data.Books.History, function(book) { return _.contains(book.Tags, "Indian"); })

Resources