How to query Map values from the Daml through JSonApi? - daml

I have tried to query Daml template text-Map it throwing me empty set instead of giving that particular data-
for Example:
"Data": [
{ "information":"XYZ",
{
"textMap": {
"Type": {
"_1": "A",
"_2": "B"
},
"Date": {
"_1": "2019-11-29",
"_2": "AMD"
},
}
}
}}
]
here,in the above sample i tried to query only using type key but it is not throwing any data related to that particular key,but when i sending both key values of Map i can able to get that particular data.but i want to send only one key value inside of that Map for querying it.how can achieve this in daml.

TextMap behaves similar to lists in the query API. A map is a value, which you can match on as a whole only. You can see the behaviour for lists here.
Suppose you have a simple TextMap in a template:
daml 1.2
module Main where
import DA.TextMap as Map
template T
with
p : Party
m : TextMap Int
where
signatory p
setup = scenario do
p <- getParty "p"
submit p do
create T with
p
m = Map.fromList [
("one", 1),
("two", 2)
]
The call to contracts/search with the below payload will match.
{
"%templates": [
{
"moduleName": "Main",
"entityName": "T"
}
],
"m" : {
"two": "2",
"one": "1"
}
}
Even though the order of the map items is switched around, the argument for m represents the same map, so the values are equal.
However, changing to simply "m" : { "one" : "1" } will not match. We are querying for a contract of type T with a map with only one entry "one".
There are currently no query options for "containsKey" or "contains".

Related

Use Doctrine to search into a json database column

I have a Symfony 3.2 project, and I need to filter data from a json column.
Given that we have an entity named "pack" with a json column named "settings" containing this kind of data:
{
"name": "My pack",
"blocks": [
{
"name": "Block 1",
"fields": [
{"label": "A", "value": "57"},
{"label": "B", "value": "100"}
]
},
{
"name": "Bock 2",
"fields": [
{"label": "C", "value": "80"}
]
}
]
}
I have to search packs with a field which has the label "B" and its value at "100", but each pack doesn't have same blocks and fields order.
So in my repository, using Doctrine\ORM\EntityRepository and opsway/doctrine-dbal-postgresql (for GET_JSON_FIELD and GET_JSON_OBJECT functions), this kind of condition works:
use Doctrine\ORM\EntityRepository;
class Packs extends EntityRepository
{
public function findFiltered(...)
{
return $this->createQueryBuilder('pack')
->andWhere("GET_JSON_FIELD(GET_JSON_OBJECT(pack.settings, '{blocks,0,fields,1}'), 'label') = :label")
->andWhere("GET_JSON_FIELD(GET_JSON_OBJECT(pack.settings, '{blocks,0,fields,1}'), 'value') = :value")
->setParameter('label', 'B')
->setParameter('value', '100')
;
}
}
But the problem is that I have to specify the precise block (the first block object), and the precise field (the second field object of the first block object). And my two condition aren't connected, it search if there is a label "B", then it search if there is a value "100". When I would like to have a research in all blocks and fields to find the good label for the good value. Any idea?
I found the good SQL request for my problem:
SELECT *
FROM pack p, json_array_elements(p.settings#>'{blocks}') blocks, json_array_elements(blocks#>'{fields}') fields
WHERE fields->>'label' = 'B' and fields->>'value' = '100';
But how I do that with doctrine?
Maybe this link can help you, it is a custom filter for a JSON type field, maybe it will serve as an example, but these functions with this bundle solved the problem for me. I hope this helps someone else too. Cheers!

Postgres - updating an array element in a json column

I have a json column in a postgres table.
The column contains the following json data:
{
"data": {
"id": "1234",
"sites": [
{
"site": {
"code": "1",
"display": "Site1"
}
},
{
"site": {
"code": "2",
"display": "Site2"
},
"externalSite": true
},
{
"site": {
"code": "3",
"display": "Site3"
}
}
]
}
}
I need to create an update query that adds another attribute ('newAttribute' in the sample below) to all array items that have '"externalSite": true', so, after running the update query the second array element will be:
{
"site": {
"code": "2",
"display": "Site2"
},
"externalSite": true,
"newAttribute": true
}
The following query returns the array elements that need to be updated:
select * from myTable, jsonb_array_elements(data -> 'sites') sites
where sites ->'externalSite' = 'true'
What is the syntax of the update query?
Thanks
Kobi
Assuming your table is called test and your column is called data, you can update it like so:
UPDATE test SET data =
(select jsonb_set(data::jsonb, '{"data","sites"}', sites)
FROM test
CROSS JOIN LATERAL (
SELECT jsonb_agg(CASE WHEN site ? 'externalSite' THEN site || '{"newAttribute":"true"}'::jsonb
ELSE site
END) AS sites
FROM jsonb_array_elements( (data#>'{"data","sites"}')::jsonb ) as ja(site)
) as sub
);
Note that I cast the data to jsonb data as there are more functions and operators available for manipulating jsonb than plain json.
You can run the SELECT statement alone to see what it is doing, but the basic idea is to re-create the sites object by expanding it with jsonb_array_elements and adding the newAttribute attribute if externalSite exists.
This array is then aggregated with jsonb_agg and, finally, in the outer select, the sites object is replaced entirely with this newly computed version.

typeahead nested json object

I am new to Ember and JSON. I want to parse a JSON object that is below with typeahead library
and access nested object values by searching their keys.
I have this Json format:
return [
{
"id": 1,
"category_name": "Supermarket",
"category_description": "SUPER MARKET",
"image_url": "",
"merchants": [
{
"name": "CARREFOUR",
"id": 12,
"merchant_type_id": 1,
"merchant_type_description": "Gold",
"merchant_redeption_rate": 0.002500,
"image_url": "https://jpg",
"branches": [
{
"id": 123456,
"latitude": 37.939483,
"area": "ΑΓ. ΔΗΜΗΤΡΙΟΣ",
"zip": "12345"
},
{
"id": 4567890,
"longitude": 23.650622,
"area": "ΑΓ. ΙΩΑΝΝΗΣ ΡΕΝΤΗΣ",
"zip": "12345"
}
]
},
{
"name": "CAFCO",
"id": 13,
"merchant_type_id": 3,
"merchant_type_description": "None",
"merchant_redeption_rate": 0.002500,
"image_url": "https:.jpg",
"branches": [
{
"id": 127890,
"latitude": 38.027870,
"area": "ΠΕΡΙΣΤΕΡΙ",
"zip": "12345"
}
]
}
]
},
{
"id": 2,
"category_name": "Πολυκαταστήματα",
"category_description": "ΠΟΛΥΚΑΤΑΣΤΗΜΑ",
"image_url": "",
"merchants": [
{
"name": "AGGELOPOYLOS CHR.",
"id": 15,
"merchant_type_id": 2,
"merchant_type_description": "Silver",
"merchant_redeption_rate": 0.002500,
"image_url": "https://www.nbg.gr/greek/retail/cards/reward-programmes/gonational/PublishingImages/aggelopoulos.jpg",
"branches": [
{
"id": 234780,
"latitude": 35.366118,
"longitude": 24.479461,
"address": "ΕΘΝ. ΜΑΚΑΡΙΟΥ 9 & ΕΛ. ΒΕΝΙΖΕΛΟΥ 1",
"area": "Ν. ΦΑΛΗΡΟ",
"zip": "12345"
}
]
}
]
}
];
--------------------------Updated----------------------------
For example, i want to search using typeahead the name of merchants and when the letter we write to search matches the name of merchants it will appear the corresponding category_name and backwards.
Example -> when i keyboard the s it will appear :
Category : Supermarket,
Name: CARREFOUR
Name: CAFCO
And the same output on the dropdown of search when i keyboard the letter c.
Any help?
New Jsbin example
The simplest way (in my mind) to get this to work is to create a computed property that will contain an array of latitudes. But how do we get there?
To get to latitude, you need to go through array of merchants and then array of branches. Being that this will be across multiple elements, you are going to end up with "array of arrays" type data structure, which is annoying to deal with. So, to simplify this, we can create a simple flatten function as follows:
flatten: function(origArray){
var newArr = [];
origArray.forEach(function(el) {
el.forEach(function(eachEl){
newArr.push(eachEl);
});
});
return newArr;
},
In addition to our function above, Ember already provides us with many other useful functions that can be used on arrays (see here). One of those is mapBy(property) which transforms an array into another array only keeping the values of the property we specified.
So, to create a lats (for latitudes) property, we can just do this:
lats: function(){
var merchantsArr = this.get('model').mapBy('merchants');
merchantsArr = this.flatten(merchantsArr);
var branchesArr = merchantsArr.mapBy('branches');
branchesArr = this.flatten(branchesArr);
return branchesArr.mapBy("latitude").compact();
}.property('model')
Above, I am basically using mapBy, flatten (see above) and compact which
Returns a copy of the array with all null and undefined elements removed.
Once you have the lats property with all the necessary data, the rest is easy.
Your call to component becomes:
{{x-typeahead data=lats name='category_name' selection=myColor}}
Note lats instead of model you originally were passing into the component.
And now, to access the value of data property in the component, you do
`this.get('data')`
which you can just pass in as the source like so:
source: substringMatcher(self.get('data'))
Working solution here
Update
Updating my answer based on your updated question.
OK, so this is getting a little more complicated. You now need more than just one property (latitude) from the object. You need category_name and merchant name.
In addition to mapBy, which just grabs one property out of array, Ember also has map which lets you transform the array into pretty much anything you want to:
lats: function(){
var merchantsArr = this.get('model').map(function(thing){
var category_name = thing.category_name;
return thing.merchants.map(function(merchant){
return {
"name": merchant.name,
"category": category_name
};
});
});
merchantsArr = this.flatten(merchantsArr);
return merchantsArr;
}.property('model')
The code above looks complicated, but it's basically just returning an array of top level objects' merchants accompanied by category_name. Since this is an array of arrays, we will need to flatten it.
Then, inside the component, we need to keep in mind that we are not just passing in an array of strings, but rather we are passing in an array of objects. Therefore, we need to look through object's properties (name and category) for a match
$.each(strs, function(i, str) {
if (substrRegex.test(str.name) || substrRegex.test(str.category)) {
matches.push(str);
}
});
Lastly, to actually display both category and merchant name, you need to tell Typeahead how to do that:
templates: {
suggestion: Handlebars.compile('<p>{{name}} – {{category}}</p>')
}
Working solution here

Json array in mongoDB

I want to get objects according to an ID they have in an array in a json file in mongodb.
I tried a lot of ways to get them with no success:
db.collection.find({"Id":"2"})
db.collection.find({"Messages.Id":"2"})
db.collection.find({"Messages":{$elemMatch:{"Id":"2"}}})
db.collection.find({"Messages.Id":{$elemMatch:{"Id":"2"}}})
{
"Messages" : [
{
"text":"aaa",
"Id" : [ "1", "2" ]
},
{
"texts" : "bbb",
"Id" : [ "1", "3" ]
}
]
}
Even though that's how it's supposed to be done according to the mongodb documentation.
So I thought something was wrong with my json design (I tried changing it but that didn't help either).
Can anyone suggest to me a good design or query to get the objects with a certain id will work?
UPDATE:
I want for example that if in the query i request the id 2
only the first message and all of it will be displayed (I don't mind if the Id field wont be displayed)
{
"text":"aaa",
"Id":["1","2"]
}
To find single elements that match you will need to utilize the positional operator ($).
db.collection.find({"Messages.Id": "2"}, {"Messages.$": 1, _id: 0})
For finding multiple matches, you would use the aggregation pipeline:
db.collection.aggregate([
{ $unwind: "$Messages" },
{ $match: {"Messages.Id": "1"}},
{ $group: { _id: null, messages: { $push: "$Messages"}}}
])

Freebase: working with "namespace-prefix key" Json Object

I have made a request to freebase API, and the query is:
{
"id" : "/m/01f8mn",
"key" : [{
"namespace" : "/wikipedia/en_id",
"value" : null
}],
"key" : [{
"namespace" : "/authority/mobygames/game",
"value" : null
}]
}​
And I got the answer from Freebase:
{
"code": "/api/status/ok",
"result": {
"id": "/m/01f8mn",
"key": [{
"namespace": "/wikipedia/en_id",
"value": "213502"
}],
"ns0:key": [{
"namespace": "/authority/mobygames/game",
"value": "prince-of-persia"
}],
"ns1:key": [{
"namespace": "/authority/giantbomb/game",
"value": "61-2561"
}]
},
"status": "200 OK",
"transaction_id": "cache;cache03.p01.sjc1:8101;2012-05-20T18:37:04Z;0060"
}
As you can notice, there is a "namespace prefix" key in the result ("ns0:key", "ns1:key")
The question is: how can I handle this with Javascript Object? Can anyone help?
When accessing properties with special characters in the name, access it as you would an associative array property:
yourObject.result["ns0:key"]
Since the namespace and value properties are stored inside of an object that is the first index of an array, to access the namespace and value, use the following syntax:
yourObject.result["ns0:key"][0].namespace
yourObject.result["ns0:key"][0].value // contains "prince-of-persia"
yourObject.result["ns1:key"][0].namespace
yourObject.result["ns1:key"][0].value // contains "61-2561"
Your initial query isn't valid JSON (the two "key" keys will overwrite each other), so I suspect there's an intermediary software layer involved (perhaps Freebase's query editor?).
If it would help to be able to control the prefixes (they're not really namespaces), you can make them up yourself to suit you. Use "key" and "other:key" or whatever scheme works for you. You could also re-write the query using the |= operator so you can specify both namespaces in a single key clause (e.g. "key":[{"namespace|=" :[ns1,ns2]}]).
for ( key in freebaseResult.result ) {
var i, resultArray = freebaseResult.result[key];
for ( i = 0; i < resultArray.length; i++ ) {
alert( resultArray[i].namespace + ": " + resultArray[i].value );
}
}