How to parse json to get key whose value is an array? - arrays

I have the following json: I need to get the value of key "GlossSeeAlso" which is an array and to traverse through it. Can someone pls guide me how it can be done?
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"ID": "44",
"str": "SGML",
"GlossSeeAlso": [
{
"GML": "111",
"XML": "222"
},
{
"GML": "123",
"XML": "322"
}
]
},
"GlossSee": "markup"
}
}
}
}
}

You can get the value with yourjsonelement.GlossSeeAlso and traverse through the array with:
for(var k in yourjsonelement.GlossSeeAlso) {
//do something with array element k.GML and k.XML
}

Related

How to filter JSON data based on another JSON data in typescript

I have 2 JSON Data 1. Payers 2. Rules. I need to filter Payers JSON data based on PayerId from Rules JSON data.
{
"Payers": [
{
"payerId": "12345",
"name": "Test Payer1"
},
{
"payerId": "23456",
"name": "Test Payer2",
},
{
"payerId": "34567",
"name": "Test Payer3"
}}
Rules JSON file
{
"Rules": [
{
"actions": {
"canCopyRule": true
},
"RuleId": 123,
"description": "Test Rule",
"isDisabled": false,
"Criteria": [
{
"autoSecondaryCriteriaId": 8888,
"criteriaType": { "code": "primaryPayer", "value": "Primary Payer" },
"payerId": ["12345", "34567"]
}
]
}
}]}
I need to filter Payers JSON data based on Rules JSON data if PayerID matches
I need output like below
{
"Payers": [
{
"payerId": "12345",
"name": "Test Payer1"
},
{
"payerId": "34567",
"name": "Test Payer3"
}
}
How to filter?
You can use Array.filter like that (based on your data structure):
const filteredPayers = payersObj.Payers.filter((p) => rulesObj.Rules[0].Criteria[0].payerId.includes(p.payerId));
I can't figure out why your Rules json looks like this, I guess you have multiple rules. If so, you will need to iterate over each rule and invoke includes. Same for Criteria.
Code will check each rule and each critirias
and will return payers if payerId found in any of the given rules of any criteria
const payers = {
"Payers": [
{
"payerId": "12345",
"name": "Test Payer1"
},
{
"payerId": "23456",
"name": "Test Payer2",
},
{
"payerId": "34567",
"name": "Test Payer3"
}]}
const rules = {
"Rules": [
{
"actions": {
"canCopyRule": true
},
"RuleId": 123,
"description": "Test Rule",
"isDisabled": false,
"Criteria": [
{
"autoSecondaryCriteriaId": 8888,
"criteriaType": { "code": "primaryPayer", "value": "Primary Payer" },
"payerId": ["12345", "34567"]
}
]
}
]
}
const data = payers.Payers.filter(payer => rules.Rules.findIndex(rule => rule.Criteria.findIndex(criteria => criteria.payerId.includes(payer.payerId)) != -1) !== -1)
console.log(data)

How can i filter the un matched array elements alone when compare with another array objects in angular 8

I have a two array response and I would like to compare the two responses and have to filter the unmatched array elements into a new array object.
Condition to compare the two response and filter is: we have to filter when code and number are not matched exactly with the response two then we have to filter such an array element into a new array object which I need as an output.
The Array element present in the Response two example is also present in the Response of Array One example which I don't want and I need to filter the array elements which is not matched with the Response of Array One.
Final Output which we filtered from the response two array will be like below which is unmatched with the response 1 array object:
{
"unmatchedArrayRes": [
{
"code": "08",
"number": "2323232323",
"id": "432",
"value": "value432"
}
]
}
Response of Array One
{
"MainData": [
{
"DataResponseOne": [
{
"viewData": {
"number": "11111111111111",
"code": "01"
},
"name": "viewDataOne"
},
{
"viewData": {
"number": "22222222222222",
"code": "01"
},
"name": "viewDataTwo"
},
{
"viewData": {
"number": "3333333333333",
"code": "02"
},
"name": "viewDataThree"
}
]
},
{
"DataResponseTwo": [
{
"viewData": {
"number": "5555555555555",
"code": "9090"
},
"name": "viewDataFour"
},
{
"viewData": {
"number": "6666666666666",
"code": "01"
},
"name": "viewDataFive"
},
{
"viewData": {
"number": "8888888888888",
"code": "01"
},
"name": "viewDataSix"
}
]
}
]
}
Response Two Example :
{
"compareRes": [
{
"code": "01",
"number": "11111111111111",
"id": "123",
"value": "value123"
},
{
"code": "9090",
"number": "5555555555555",
"id": "345",
"value": "value567"
},
{
"code": "08",
"number": "2323232323",
"id": "432",
"value": "value432"
}
],
"metaData": "343434343434"
}
First, create a combined list of all the view items from response one.
const combinedList = [];
res1["MainData"].forEach(data => {
// console.log(data);
for( let key in data) {
// console.log(key);
data[key].forEach(innerData => {
console.log(innerData)
combinedList.push(innerData["viewData"]);
})
}
});
In the above method, It is done in such a way that it can handle multiple viewData responses like DataResponseOne, DataResponseTwo, and so on.
And then filter second response Items like this:
const unfilteredListItems = res2["compareRes"].filter(data => {
return !combinedList.some(listItem => {
return listItem.code === data.code && listItem.number === data.number;
});
});
console.log(unfilteredListItems);
Working Stackblitz link: https://stackblitz.com/edit/ngx-translate-example-aq1eik?file=src%2Fapp%2Fapp.component.html

How to aggregate a MongoDB query to remove the usage of a for loop?

I am new to MongoDB and am working with it on NodeJS code.
As you can see the below code, I am running a for loop through my books collection to figure out the latest version of the query_book.
I know that this isn't efficient, and want to understand how can an aggregation function be written for it in MongoDB.
Current code:
let result= {};
_.forEach(books, function(query_book)
{
if(!result[query_book.book_id])
{
result[query_book.book_id] = query_book
}
else if(result[query_book.book_id].book_version <
query_book.book_version)
{
result[query_book.book_id] = query_book
}
Data Object for books:
[
{
"book_id": "ab12nld”,
"book_version": "0”,
"author": “Sam”,
“name”: “Sample Book”,
“comments”: “Done”
},
{
"book_id": "ab12nld”,
"book_version": "1",
"author": "Martin",
"name": "Sample Book",
“comments”: “In Progress”
},
{
"book_id": "ab12nld”,
"book_version": "2",
"author": "Roy",
"name": "Sample Book",
“comments”: “To-Do”
}
]
[
{
"book_id": "bcj123n”,
"book_version": "0”,
"author": “Don”,
“name”: “Another Book”,
“comments”: “Done”
},
{
"book_id": "bcj123n”,
"book_version": "1",
"author": "Ray",
"name": "Another Book",
“comments”: “In Progress”
},
{
"book_id": "bcj123n”,
"book_version": "2",
"author": "Max",
"name": "Another Book",
“comments”: “To-Do”
}
]
In this case, I want to fetch the object having the maximum value of book_version for my input book_id which is ab12nld:
{
"book_id": "ab12nld”,
"book_version": "2",
"author": "Roy",
"name": "Sample Book",
“comments”: “To-Do”
}
If using Node.js Mongo driver (replace [bookId] with your input)
db.collection('books')
.findOne({ book_id: [bookId] }, { sort: [['book_version', -1]] })
Or, if using Mongoose,
Book.findOne({ book_id: [bookId] }).sort({ book_version: -1 })
db.books.aggregate([{ "$sort": { "book_version": -1 } },{"$limit":1}])
I understood that you want to retrieve a document having highest value of a field.
Here, the document having the highest value in the version field. The simplest way of doing this is to sort in reverse order and get the first document.
You can also use the aggregate method.
Try the following snippet. I think it will help.
db.books.find().sort({"book_version":-1}).limit(1);

How to filter embedded array in mongo document with morphia

Given my Profile data looks like below, I want to find the profile for combination of userName and productId
and only return the profile with the respective contract for this product.
{
"firstName": "John",
"lastName": "Doe",
"userName": "john.doe#gmail.com",
"language": "NL",
"timeZone": "Europe/Amsterdam",
"contracts": [
{
"contractId": "DEMO1-CONTRACT",
"productId": "ticket-api",
"startDate": ISODate('2016-06-29T09:06:42.391Z'),
"roles": [
{
"name": "Manager",
"permissions": [
{
"activity": "ticket",
"permission": "createTicket"
},
{
"activity": "ticket",
"permission": "updateTicket"
},
{
"activity": "ticket",
"permission": "closeTicket"
}
]
}
]
},
{
"contractId": "DEMO2-CONTRACT",
"productId": "comment-api",
"startDate": ISODate('2016-06-29T10:27:45.899Z'),
"roles": [
{
"name": "Manager",
"permissions": [
{
"activity": "comment",
"permission": "createComment"
},
{
"activity": "comment",
"permission": "updateComment"
},
{
"activity": "comment",
"permission": "deleteComment"
}
]
}
]
}
]
}
I managed to find the solution how to do this from the command line. But I don't seem to find a way how to accomplish this with Morphia (latest version).
db.Profile.aggregate([
{ $match: {"userName": "john.doe#gmail.com"}},
{ $project: {
contracts: {$filter: {
input: '$contracts',
as: 'contract',
cond: {$eq: ['$$contract.productId', "ticket-api"]}
}}
}}
])
This is what I have so far. Any help is most appreciated
Query<Profile> matchQuery = getDatastore().createQuery(Profile.class).field(Profile._userName).equal(userName);
getDatastore()
.createAggregation(Profile.class)
.match(matchQuery)
.project(Projection.expression(??))
Note... meanwhile I found another solution which does not use an aggregation pipeline.
public Optional<Profile> findByUserNameAndContractQuery(String userName, String productId) {
DBObject contractQuery = BasicDBObjectBuilder.start(Contract._productId, productId).get();
Query<Profile> query =
getDatastore()
.createQuery(Profile.class)
.field(Profile._userName).equal(userName)
.filter(Profile._contracts + " elem", contractQuery)
.retrievedFields(true, Profile._contracts + ".$");
return Optional.ofNullable(query.get());
}
I finally found the best way (under assumption I only want to return max. 1 element from array) to filter embedded array.
db.Profile.aggregate([
{ $match: {"userName": "john.doe#gmail.com"}},
{ $unwind: "$contracts"},
{ $match: {"contracts.productId": "comment-api"}}
])
To match according to your first design you could try the projection settings with morphia aggregation pipeline.
Query<Profile> matchQuery = getDatastore().createQuery(Profile.class).field(Profile._userName).equal(userName);
getDatastore()
.createAggregation(Profile.class)
.match(matchQuery)
.project(Projection.expression("$filter", new BasicDBObject()
.append("input", "$contracts")
.append("as", "contract")
.append("cond", new BasicDBObject()
.append("$eq", Arrays.asList('$$contract.productId', "ticket-api")));
Also see the example written by the morphia crew around line 88 at https://github.com/mongodb/morphia/blob/master/morphia/src/test/java/org/mongodb/morphia/aggregation/AggregationTest.java.

Insert object in nested array mongodb nodejs

So I am trying to insert an object in parameters and have been unsuccessful. My mongodb structure looks like this:
[
{
"_id": "04",
"name": "test service 4",
"id": "04",
"version": "0.0.1",
"title": "testing",
"description": "test",
"protocol": "test",
"operations": [
{
"_id": "99",
"oName": "test op 52222222222",
"sid": "04",
"name": "test op 52222222222",
"oid": "99",
"parameters": {},
"description": "testing",
"returntype": "test"
},
{
"_id": "58",
"oName": "test op 52222222222",
"sid": "04",
"name": "test op 52222222222",
"oid": "58",
"parameters": {},
"description": "testing",
"returntype": "test"
}
]
}
]
I want to be able to add an object into parameters with basic details such as name, id, and type. I am not entirely sure how to tackle this as I have all other CRUD operations implemented up until the parameters part. How should I go about to complete this? I know mongodb has issues when trying to insert something into an array inside an array, so if anyone has any suggestions as to how I can complete this I would really appreciate it. Thanks.
One of the problems is I do not have access to the _id of the root object, but I do have the _id for the operation where I am inserting the parameter. Hence I was trying to insert the parameter using this code:
collection.update({"operations":{"$elemMatch": {"oid": oid}}}, {'$addToSet':{"operations.parameters": {name: "test"} }}, {safe:true}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred'});
} else {
res.send(result[0]);
}
});
This does not work though.
I was able to complete the insert by using the following code:
collection.update({ "operations": {$elemMatch: {_id:oid}}}, {$addToSet: { "operations.$.parameters" : parameter}}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred'});
} else {
res.send(result[0]);
}
});
Just in case anyone needed it.
This is because you need to use positional operator, The example I am copying from the link is almost the same as in your case:
db.students.update(
{ _id: 4, "grades.grade": 85 },
{ $set: { "grades.$.std" : 6 } }
)

Resources