JsonPath - Filter Array and get only the first element - arrays

Im trying to filter the elements of this JSON array to return only the first element it will find.
{
"elements": [{
"urn": "urn:li:lyndaCourse:189800",
"details": {
"classifications": [{
"associatedClassification": {
"urn": "urn:li:lyndaCategory:9331",
"type": "LIBRARY"
}
},
{
"associatedClassification": {
"urn": "urn:li:lyndaCategory:8982",
"type": "SUBJECT"
}
},
{
"associatedClassification": {
"urn": "urn:li:lyndaCategory:8920",
"type": "LIBRARY"
}
}
]
}
}]
}
But this results in an EMPTY array [].
I tried this JSONPATH query in https://jsonpath.herokuapp.com/
$.elements[0].details.classifications..associatedClassification[?(#.type=='LIBRARY')][0]
Expecting to get:
[{
"urn": "urn:li:lyndaCategory:9331",
"type": "LIBRARY"
}]

Another way to filter the information is by filtering the property "classification" (without using ".."), and use "associatedClassification.type" in your filter, so you should have something like this:
$.elements[0].details.classifications[?(#.associatedClassification.type=='LIBRARY')]
With the above JSONPATH you will have all items which type is "LIBRARY" (in your example will return 2 items).
You mentioned you need only the first one of the filtered items, as far as I investigated it seems there's no posible solution to return only the first item using only JSONPATH (see the thread bellow):
https://github.com/json-path/JsonPath/issues/272

The following works on all elements:
$..classifications[?(#.associatedClassification.type=='LIBRARY')]
and returns a list of all matching associatedClassification objects.
JSONPath is expected to point inside the original document. Therefore, getting the first element from the result list would require post-processing, e.g. a separate JSONPath, e.g.
$.[0]

Related

MongoDB aggregation for finding an index of array nested object with $gt condition

I am trying to get the positional index of an array element (to push more elements at $position). I'm specifically targeting a single document (say, id=x)
Simplified document:
{
id:"x",
samples:[{"timestamp":123},{"timestamp":234},{"timestamp":345}}
}
Aggregation pipeline:
collection.aggregate([{"$match": {"id": "x"}},
{"$project": {"matchedIndex": {"$indexOfArray": ["$samples.timestamp", 234]}}}])
This works to return matchedIndex=1 .
Now I would like to find the index of 'samples' where timestamp is greater than say 235, which should return '2'
I have tried combinations of:
collection.aggregate([{"$match": {"UUID": "5fd41e35-5e49-O977-t091-6f228bc65e37"}},
{"$project": {"matchedIndex":
{"$indexOfArray": ["$samples.timestamp",
{"$gt": ["$$timestamp", 235]}]}}}])
I understand this wont work, I'm just not sure how to go about it.
The purpose is to insert many elements between timestamps. Maybe there is a better way entirely to do this. Thanks
Instead of using "$samples.timestamp" as first argument you can use $map there to transform it into an array of true and false values depending on your condition, try:
{
"$project": {
"matchedIndex": {
"$indexOfArray": [
{ $map: { input: "$samples.timestamp", in: { $gte: [ "$$this", 235 ] } } },
true
]
}
}
}
Mongo Playground

Delete many items from array of documents in mongodb that match this value

I am trying to delete all documents from an array of documents that match this value but cannot figure it out,
This is my delete query that is not working, courses is the array I need to be in and code is the document I need to check to see its value for deletetion. So if courses.code == 123, then delete and keep going sort of thing.
result = await mongoClient.db(DB_NAME).collection("technologies").deleteMany({ 'courses': {$in: 'courses.code'} });
That is what it looks like in my collection.
"name": "Sass",
"description": "Sass (Syntactically awesome style sheets) is a preprocessor scripting language that is interpreted or compiled into Cascading Style Sheets (CSS).",
"difficulty":2,
"courses":[
{"code":"PROG2700","name":"Client Side Programming"},
{"code":"PROG3017","name":"Full Stack Programming"}
]
},
Any help would be great, thanks!
You can filter documents that contain the field you want to update
Do tests before updates on the original collection.
After some searches, I've found this method:
const filter = { }
db.collection.update(filter,
{
$pull: {
"courses": {
code: {
$in: [
"PROG3017",
"PROG2700"
]
}
}
}
},
{
multi: true
})
This pulls out any element in the array where the value of code is $in the array.

How to iterate through a JSON array and display specific information based on an API response value in React?

I'm building a ReactJS web application, I have a JSON array:
[{
"2149166938": {
"name": "Classical-42",
"icon": "/common/destiny2_content/icons/e6885dab15cafeaf0dbf80f1ff9b5eb8.jpg"
},
"2149166939": {
"name": "Countess SA/2",
"icon": "/common/destiny2_content/icons/de8906743db9fce201b33802c8498943.jpg"
},
"2154059444": {
"name": "The Long Goodbye",
"icon": "/common/destiny2_content/icons/fe07633a2ee87f0c00d5b0c0f3838a7d.jpg"
}
}]
When I make a call to an API I am returned a value of lets say 2154059444 which is the same value as the last object in my JSON file.
How would I iterate through the JSON file to find the object which has a value of 2154059444 and then access and render it's child values like name or icon?
you can do something like this. Your array is not proper please edit.
Create filtered data :
//here i am addding single dummy point you can make your function
l
et filteredData = [].concat(data.map(test => {
if(Object.keys(test)[0]==="2154059444"){
return test["2154059444"]
}
})).filter(Boolean)
and simply render it app like this .
{ filteredData.map(test => <div>{test.name}</div>)}
Here is live link
This is simple. JSON is equivalent to Javascript object. So you can do something like result[0]["2154059444"]. You might want to use JSON.parse for converting the JSON string to Javascript object.

Elasticsearch - Filter where (one of nested array) and (all of nested array)

TL;DR - How do I check whether one-of and all-of a nested array meet specified criteria?
I have a document. Each document has an array of nested outer objects, who themselves have a list of nested inner objects. I need to perform a filter for all documents where at least one of the document's outer nested objects match. When I say match, I mean that all the outer nested objects' inner objects match in some way. Here's an example mapping for reference;
{ "document" : {
"properties" : {
"name" : {
"type" : "string"
},
"outer" : {
"type" : "nested",
"properties" : {
"inner" : {
"type" : "nested",
"properties" : {
"match" : {
"type" : "string",
"index" : "not_analyzed"
},
"type" : {
"type" : "string",
"index" : "not_analyzed"
}
}}}}}}
}
If the document has no outer/inner objects it is considered to match. But to make things worse the inner objects need to be considered to match differently depending on the type in a kind of conditional logic manner (eg CASE in SQL). For example, if the type were the term "Country" then inner object would be considered to match if the match were a specified country code such as ES. A document may have inner objects of varying type and there is not guarantee that specific types will exist.
Coming from a imperative (Java) programming background I am having incredible trouble figuring out how to implement this kind of filtering. Nothing I can think of even vaguely matches this behaviour. Thus far all I have is the filtered query;
"filtered" : {
"query" : {
"match_all" : { }
},
"filter" : {
"bool" : {
"should" : {
"missing" : {
"field" : "outer.inner.type"
}
}}}}
}
So, the question is...
How can I filter to documents who have at least one outer object which has all inner objects matching based on the type of inner object?
Further details By Request -
Example Document JSON
{
"name":"First",
"outer":[
{
"inner":[
{"match":"ES","type":"Country"},
{"match":"Elite","type":"Market"}
]
},{
"inner":[
{"match":"GBR","type":"Country"},
{"match":"1st Class","type":"Market"},
{"match":"Admin","type":"Role"}
]
}
],
"lockVersion":0,"sourceId":"1"
}
The above example should come through the filter if we were to provide "1st Class" market and the country "GRB" because the second of the two outer objects would be considered a match because both inner objects match. If, however, we provided the country country "GRB" and the market "Elite" then we would not have this document returned because neither of the outer objects would have bother of their inner objects match in their entirety. If we wanted the second outer object to match then all three inner would need to match. Take note that there is an extra type in the third inner. This leads to a situation where if a type exists then it needs to have a match for it else it doesn't need to match because it is absent.
One of Nested Array
Having one of a nested array matching some criteria turns out to be very simple. A nested filter evaluates to matching/true if any of the array of nested objects match the specified inner filters. For example, given an array of outer objects where one of those objects has a field match with the value "matching" the following would be considered true.
"nested": {
"path": "outer",
"filter": {
"term" : { "match" : "matching" }
}
}
The above will be considered true/matching if one of the nested outer objects has a field called match with the value "matching".
All of Nested Array
Having a nested filter only be considered matching if all of the nested objects in an array match is more interesting. In fact, it's impossible. But given that it is considered matching if only one of the nested objects match a filter we can reverse the logic and say "If none of the nested objects don't match" to achieve what we need. For example, given an array of nested outer.inner objects where all of those objects has a field match with the value "matching" the following would be considered true.
"not" : {
"nested": {
"path": "outer.inner",
"filter": {
"not" : {
"term" : { "match" : "matching" }
}
}
}
}
The above will be considered true/matching because none of the nested outer.inner objects don't (double negative) have a field called match with the value "matching". This, of course, is the same as all of the nested inner objects having a field match with the value "matching".
Missing Any Nested Objects
You can't check whether a field containing nested objects is missing using the traditional missing filter. This is because nested objects aren't actually in the document at all, they are stored somewhere else. As such missing filters will always be considered true. What you can do however, is check that a match_all filter returns no results like so;
"not": {
"nested": {
"path": "outer",
"filter": {
"match_all": {}
}
}
}
This is considered true/matching if match_all finds no results.
Well, it's a doozy, but this query seems to do what you want:
POST /test_index/_search
{
"query": {
"filtered": {
"filter": {
"nested": {
"path": "outer",
"filter": {
"bool": {
"must": [
{
"nested": {
"path": "outer.inner",
"filter": {
"bool": {
"must": [
{ "term": { "outer.inner.type": "Market" } },
{ "term": { "outer.inner.match": "1st Class" } }
]
}
}
}
},
{
"nested": {
"path": "outer.inner",
"filter": {
"bool": {
"must": [
{ "term": { "outer.inner.type": "Country" } },
{ "term": { "outer.inner.match": "GBR" } }
]
}
}
}
}
]
}
}
}
}
}
}
}
Here is some code I used to test it:
http://sense.qbox.io/gist/f554c2ad2ef2c7e6f5b94b1ddb907813370f4edc
Let me know if you need some explanation of the logic; it is kind of involved.

JsRender - dynamic array, helper function

I have a website with JsRender and a JSON file.
My JSRender code:
{{for ~getModel(cards)}}
{{:id}}
{{/for}}
My JSON file:
{
"alpha": {
"cards": [{
"id": "alpha-01"
}, {
"id": "alpha-02"
}, {
"id": "alpha-03"
}]
},
"beta": {
"cards": [{
"id": "beta-01"
}, {
"id": "beta-02"
}]
}
}
In {{for ~getModel(cards)}} is cards, a suffix.
My JsRender helper concatenates a prefix and a suffix and the result is a string.
This string should be my array for the for loop. The suffix is a dynamic part, a parameter from the URL (?model=alpha)
The for loop should run through the array alpha.cards -> {{for ~getModel(alpha.cards)}}
But when I concate the dynamic part and the suffix, the return value is a string, and the for loop doesn't work. It seems the value (return) for the helper must be an array.
Is that right or is there a another solution for the problem?
Yes - you need to return an array. JsRender renders against javascript objects and arrays (typically a hierarchy of objects and arrays). If your string is a JSON string you need to convert/eval first to produce the corresponding object or array...

Resources