Look if loopback model property array contains a string - javascript

I have a Loopback moddel that looks like this:
{
"name": "string",
"elements": [
"string"
]
}
Now I want to filter if elements property conatins a certain string.
Something like this:
User.find({
filter: {
where: {elements: $scope.objects[i].id} //doesn't work, I want sth like "element contains $scope.objects[i].id
}}, function (user) {
console.log(user);
});

Warning: This solution was meant to answer the question "how do I filter a list of objects". It was accepted so I can't remove it. I don't know anything about LoopBack which has performance implications I'm not privy to. So please keep searching if you are looking for a "LoopBack" best practice.
This seems like a javascript question to me. The elements property contains an array so you can filter that array with filter().
yourModel = { // <-- Using a plain object for demo.
"name": "string",
"elements": [
"string"
]
}
matchingElements = yourModel.elements.filter(function(elm){ return elm === $scope.objects[i].id});
didMyModelHaveTheElement = matchingElments.length > 0;

Related

Find specific JSON key and return its value in Javascript

I have some JSON from an API which I am logging in the console.
This is easy for something like the id where I can do this...
let movieID = out.id;
console.log(movieID)
But how can I also return the 'name' of the person whose job is specifically 'Director' from JSON example like this? Basically I need to do something like 'if someone has the JOB of DIRECTOR, log their name to the console.
{
"id": 37291,
"credits": {
"crew": [
{
"name": "John Smith",
"job": "Producer"
},
{
"name": "Mary Jones",
"job": "Director"
}
]
}
}
You can get the list of the crew, like you described above. Then find the first entry in that list where the job equals "Director" and put it in a variable:
let director = out.credits.crew.find(member => member.job == "Director");
You can then log the data, as you did for the movie itself.
Something like this would do literally what you asked which was to console log out the names
credits.crew.foreach((crewMember) => {
if (crewMember.job == 'Director') {
console.log(crewMember.name)
}
})
Use underscore:
_.filter(credits.crew, (key) => key.job === 'Director')
That will give you all the keys with that value. Trust me you should use underscore or lodash because objects can get super tricky and it saves you a ton of time.

Mongoose: How to extract arrays in subdocuments to a single array in the parent document

An Express server using Mongoose returns the following JSON from the database in one of its routes:
{
"gradeLevel": 12,
"classes": [
{
"className": "A",
"students": [
"student1", "student2","student3"
]
},
{
"className": "B",
"students": [
"student4", "student5","student6"
]
},
{
"className": "C",
"students": [
"student7", "student8","student9"
]
}
]
}
In the client, I'd like to be able to for example efficiently check if a student is in any of the class subdocuments in the parent document. The following are the solutions I've conceived, but am not sure which is best practice:
When a student is pushed to class subdocument, push the student to the parent's students field as well.
Add a new field in the model's toJSON transformation to compile all the students.
Use vanilla Javascript in the client to extract all students
I was at this problem too. But to tackle this you need a separate collection called allStudents for example where the schema of it is as follows
{ nameOfStudent: 'String' className: 'String' }
then aggregate it accordingly with subdoucment. So that wherever you push a new student into allStudents with the className mentioned it will be pushed to the students subdocument of the respective className.
Querying with dot notation, like
.find({"classes.students":"student8"})
will check the students field of each object in the classes array, returning the documents containing the specific student in any class.
Thank you for the answers given. Just sharing another solution using vanilla Javascript that might be of use to those in similar situations:
checkStudent = (batch, student) => {
let result = null
const inClass = (cls) => {
if (cls.students.includes(student)) {
result = cls
return true
}
return false
}
batch.classes.some(inClass)
return result
}

Query CosmosDb - where array contains item(s) from array

I don't know if there is a word for this, guess there is, but right now I couldn't explain it better than "where array contains item(s) from array".
It might sound weird, but actually it not (I think), and I'm having a hard time figuring out how I can do this in Azure CosmosDB.
Here goes. I have a document like this (simplified):
{
"id": "2a62fcf4-988f-4ebe-aedc-fb0c664b85d8",
"Title": "Seks års fængsel for overgreb",
"ZipCodes": [
{
"Code": "6500",
"Name": "Vojens",
"FoundViaTerm": "Vojens"
},
{
"Code": "6400",
"Name": "Sønderborg",
"FoundViaTerm": "Sønderborg"
},
{
"Code": "6700",
"Name": "Esbjerg",
"FoundViaTerm": "Esbjerg"
}
],
"_rid": "k1sVAPf7SQAMAAAAAAAAAA==",
"_self": "dbs/k1sVAA==/colls/k1sVAPf7SQA=/docs/k1sVAPf7SQAMAAAAAAAAAA==/",
"_etag": "\"00001000-0000-0000-0000-5a14898e0000\"",
"_attachments": "attachments/",
"_ts": 1511295374
}
Ok, now I want to query documents like this and find all, where ZipCodes.Code is in a list of zipcodes, ex. ('6500', '2700').
I'm puzzle here...
I found the ARRAY_CONTAINS method and it works, if I only come in with one zipcode - my problem is I come with a list.
Hope somebody can help, thanks in advance.
Per my experience , expr in ARRAY_CONTAINS (arr_expr, expr [, bool_expr]) method is not supported list arguments.
According to your situation , I suggest you use UDF in Cosmos DB.
I created 3 sample documents as your description.
[
{
"id": "1",
"zip": [
{
"code": "1111"
},
{
"code": "2222"
}
]
},
{
"id": "2",
"zip": [
{
"code": "2222"
},
{
"code": "3333"
}
]
},
{
"id": "3",
"zip": [
{
"code": "4444"
},
{
"code": "1111"
},
{
"code": "2222"
}
]
}
]
Please refer to the snippet of UDF code as below :
function test(zipcode){
var arrayList = ["1111","2222"]
var ret = false ;
for(var i=0 ;i <zipcode.length;i++){
if(arrayList.indexOf(zipcode[i].code)){
ret= true;
}else{
ret = false;
break;
}
}
return ret;
}
You could select zip array (select c.zip from c) ,then loop the results and invoke the UDF above in your code with the zip[i] arguments.
Hope it helps you.
Just for summary:
Use the IN operator from Cosmos DB SQL APIs to query entry which is included in the list condition.
Like
SELECT * FROM c WHERE c.ZipCodes[0].Code IN ("6500", "6700")
Or
SELECT DISTINCT c FROM c JOIN zc IN c.ZipCodes WHERE zc.Code IN ("2720", "2610")
I would like to propose another solution to this problem.
Use EXISTS with ARRAY_CONTAINS in this way:
SELECT * FROM c
WHERE EXISTS
(SELECT VALUE z FROM z in c.ZipCodes WHERE ARRAY_CONTAINS(["6500","6700"], z))
You can do something like this:
For each item in ZipCodes, you get a zip and compare with the array of codes you are checking. This, IMHO, is much better than using UDF.
{
query: '
SELECT DISTINCT value r
FROM root r
JOIN zip IN r.zipCodes
WHERE ARRAY_CONTAINS(#zipIds, zip, true)
',
parameters: [{name: "#zipIds", value: zipIds}]
}
The last param of ARRAY_CONTAINS tells the function to accept partial matches.
Apart from the fact that using UDF looks as the easier option, i would not use UDFs in your query's filter, since it compromises the performance of your query. I faced the same problem in my work environment, where things are designed to use UDFs to help in the queries, but the reality is that most of the times we are doing queries by using single values, and using UDF will actually result on the query not using the index. So in that case if you need to validate multiple values in the array, depending on the volume of values you need to validate, you can always write something like ARRAY_CONTAINS(c, 1) or ARRAY_CONTAINS(c, 2) or ....
It doesn't look so elegant solution, but will ensure that it will use the index and will do the best performance in your query.

Polymer JS reading from JSON file

I'm trying to read a sub-array from a JSON file in Polymer in JS and return the sub-array to be used in a dom-repeat. However, it tells me that the sub-array is undefined. I tried re-structuring the JSON file in various ways but no luck. I think I'm not using the right syntax somewhere.
Right now the JSON looks like this:
{
"url": "dn8",
"volpage": "DN iii 1",
"languages": [{
"pt": {
"authors": ["Laera"],
"titlelan": "Title in Portuguese"
},
"fr": {
"authors": ["Moi"],
"titlelan": "Title in French"
},
"es": {
"authors": ["Jesus"]
}
}]
}
I'm trying to get a sub-array called languageData which just hold the specific data for an input-language. The input has the correct value for the inputLanguage, like for instance "pt". My JS looks like this:
Polymer({
is: 'test-data',
properties: {
inputUrl: String,
inputLanguage: String,
inputData: {
type: Array,
notify: true,
value: function(){return []}
},
languageData: {
type: Array,
computed: '_computeLanguage(inputData,inputLanguage)'
}
},
_computeLanguage: function(inputData,inputLanguage) {
var lanarray = inputData.languages[inputLanguage];
return lanarray ? lanarray : "";
}
});
Any help is very much appreciated!
As you can see the languages property of your JSON is not an Object but and Array.
Your "Polymer code" works well, the problem is that you are trying to get the languageData as if it were an Array:
var lanarray = inputData.languages[inputLanguage];
Actually, languages contains an array of objects and you can't find your lang object in this way.
A possible solution could be:
var lanarray = inputData.languages[0][inputLanguage];

Regex for parsing single key: values out of JSON in Javascript

I'm trying to see if it's possible to lookup individual keys out of a JSON string in Javascript and return it's Value with Regex. Sort of like building a JSON search tool.
Imagine the following JSON
"{
"Name": "Humpty",
"Age": "18",
"Siblings" : ["Dracula", "Snow White", "Merlin"],
"Posts": [
{
"Title": "How I fell",
"Comments": [
{
"User":"Fairy God Mother",
"Comment": "Ha, can't say I didn't see it coming"
}
]
}
]
}"
I want to be able to search through the JSON string and only pull out individual properties.
lets assume it's a function already, it would look something like.
function getPropFromJSON(prop, JSONString){
// Obviously this regex will only match Keys that have
// String Values.
var exp = new RegExp("\""+prop+"\"\:[^\,\}]*");
return JSONString.match(exp)[0].replace("\""+prop+"\":","");
}
It would return the substring of the Value for the Key.
e.g.
getPropFromJSON("Comments")
> "[
{
"User":"Fairy God Mother",
"Comment": "Ha, can't say I didn't see it coming"
}
]"
If your wondering why I want to do this instead of using JSON.parse(), I'm building a JSON document store around localStorage. localStorage only supports key/value pairs, so I'm storing a JSON string of the entire Document in a unique Key. I want to be able to run a query on the documents, ideally without the overhead of JSON.parsing() the entire Collection of Documents then recursing over the Keys/nested Keys to find a match.
I'm not the best at regex so I don't know how to do this, or if it's even possible with regex alone. This is only an experiment to find out if it's possible. Any other ideas as a solution would be appreciated.
I would strongly discourage you from doing this. JSON is not a regular language as clearly stated here: https://cstheory.stackexchange.com/questions/3987/is-json-a-regular-language
To quote from the above post:
For example, consider an array of arrays of arrays:
[ [ [ 1, 2], [2, 3] ] , [ [ 3, 4], [ 4, 5] ] ]
Clearly you couldn't parse that with true regular expressions.
I'd recommend converting your JSON to an object (JSON.parse) & implementing a find function to traverse the structure.
Other than that, you can take a look at guts of Douglas Crockford's json2.js parse method. Perhaps an altered version would allow you to search through the JSON string & just return the particular object you were looking for without converting the entire structure to an object. This is only useful if you never retrieve any other data from your JSON. If you do, you might as well have converted the whole thing to begin with.
EDIT
Just to further show how Regex breaks down, here's a regex that attempts to parse JSON
If you plug it into http://regexpal.com/ with "Dot Matches All" checked. You'll find that it can match some elements nicely like:
Regex
"Comments"[ :]+((?=\[)\[[^]]*\]|(?=\{)\{[^\}]*\}|\"[^"]*\")
JSON Matched
"Comments": [
{
"User":"Fairy God Mother",
"Comment": "Ha, can't say I didn't see it coming"
}
]
Regex
"Name"[ :]+((?=\[)\[[^]]*\]|(?=\{)\{[^\}]*\}|\"[^"]*\")
JSON Matched
"Name": "Humpty"
However as soon as you start querying for the higher structures like "Posts", which has nested arrays, you'll find that you cannot correctly return the structure since the regex does not have context of which "]" is the designated end of the structure.
Regex
"Posts"[ :]+((?=\[)\[[^]]*\]|(?=\{)\{[^\}]*\}|\"[^"]*\")
JSON Matched
"Posts": [
{
"Title": "How I fell",
"Comments": [
{
"User":"Fairy God Mother",
"Comment": "Ha, can't say I didn't see it coming"
}
]
\{|\}|\[|\]|,|:|(\\-)?\\d+(\\.\\d+)?|".+?"
You can use the following regex and iterate with a match over all tokens of a json. You can tokenize the JSON, but the parsing part has to be implemented by you.
Since you're using JavaScript as I assume from the tags, your best way to encode the JSON stays JSON.parse().
I'm almost 10 years late to the party, but I came up with this.
Not tested in crazier JSONs than this, but it solves my use cases.
const obj1 = {
id: 1,
'name.1': '123',
address: {
'address.1': 'Chicken Dinner Road, 69',
'address.2': 'Psycho lane, 666',
},
'age.1': {
'thisIsSomeCrazyJson.3': 10,
age: 50,
},
types: [
{
id: 22,
'name.name': '123',
typeOption: {
id: 1,
'whoTFWroteThisJSON.2': '123',
},
},
{
id: 32,
'name.1': '123',
},
],
};
const obj2 = {
Name: 'Humpty',
Age: '18',
Siblings: ['Dracula', 'Snow White', 'Merlin'],
Posts: [
{
Title: 'How I fell',
Comments: [
{
'User': 'Fairy God Mother',
'Comment': "Ha, can't say I didn't see it coming",
},
],
},
],
};
function matchKeyDeep(input, pattern) {
return Object.entries(input).reduce((nextInput, [key, value]) => {
const isMatch = pattern.test(key);
if (Array.isArray(value)) {
const arrValue = value;
let nextValue = arrValue.map((arrItem) => {
if (typeof arrItem === 'object') {
return matchKeyDeep(arrItem, pattern);
}
return arrItem;
});
if (!isMatch && Array.isArray(nextValue)) {
nextValue = nextValue.filter((v) => (typeof v === 'object' && v !== null));
if (nextValue.length === 0) return nextInput;
}
nextInput[key] = nextValue;
return nextInput;
}
if (typeof value === 'object') {
const recurse = matchKeyDeep(value, pattern);
if (!isMatch && Object.keys(recurse).length === 0) {
return nextInput;
}
nextInput[key] = recurse;
return nextInput;
}
if (isMatch) {
nextInput[key] = value;
}
return nextInput;
}, {});
}
const res = matchKeyDeep(obj1, /\.\d/);
const res2 = matchKeyDeep(obj2, /Comment/);
console.log(res);
console.log(res2);
First, stringify the JSON object. Then, you need to store the starts and lengths of the matched substrings. For example:
"matched".search("ch") // yields 3
For a JSON string, this works exactly the same (unless you are searching explicitly for commas and curly brackets in which case I'd recommend some prior transform of your JSON object before performing regex (i.e. think :, {, }).
Next, you need to reconstruct the JSON object. The algorithm I authored does this by detecting JSON syntax by recursively going backwards from the match index. For instance, the pseudo code might look as follows:
find the next key preceding the match index, call this theKey
then find the number of all occurrences of this key preceding theKey, call this theNumber
using the number of occurrences of all keys with same name as theKey up to position of theKey, traverse the object until keys named theKey has been discovered theNumber times
return this object called parentChain
With this information, it is possible to use regex to filter a JSON object to return the key, the value, and the parent object chain.
You can see the library and code I authored at http://json.spiritway.co/

Categories

Resources