Does realm Javascript supports Join, Group By and Aggregation functions - react-native

To develop a React Native mobile app that shows statistics data, following functions to be used widely, does Realm will meet the needs?
Join
Group by
Aggregation
AutoIncrement
Kindly suggest any other ORM/DB that will be best fit for the statistical app?

Alternative
You can get date in Realm Database then by useign js group by
// Accepts the array and key
const groupBy = (array, key) => {
// Return the end result
return array.reduce((result, currentValue) => {
// If an array already present for key, push it to the array. Else create an array and push the object
(result[currentValue[key]] = result[currentValue[key]] || []).push(
currentValue
);
// Return the current iteration `result` value, this will be taken as next iteration `result` value and accumulate
return result;
}, {}); // empty object is the initial value for result object
};
// Group by color as key to the person array
const personGroupedByColor = groupBy(person, 'color');

Related

How do perform a graph query and join?

I apologize for the title, I don't exactly know how to word it. But essentially, this is a graph-type query but I know RavenDB's graph functionality will be going away so this probably needs to be solved with Javascript.
Here is the scenario:
I have a bunch of documents of different types, call them A, B, C, D. Each of these particular types of documents have some common properties. The one that I'm interested in right now is "Owner". The owner field is an ID which points to one of two other document types; it can be a Group or a User.
The Group document has a 'Members' field which contains an ID which either points to a User or another Group. Something like this
It's worth noting that the documents in play have custom IDs that begin with their entity type. For example Users and Groups begin with user: and group: respectively. Example IDs look like this: user:john#castleblack.com or group:the-nights-watch. This comes into play later.
What I want to be able to do is the following type of query:
"Given that I have either a group id or a user id, return all documents of type a, b, or c where the group/user id is equal to or is a descendant of the document's owner."
In other words, I need to be able to return all documents that are owned by a particular user or group either explicitly or implicitly through a hierarchy.
I've considered solving this a couple different ways with no luck. Here are the two approaches I've tried:
Using a function within a query
With Dejan's help in an email thread, I was able to devise a function that would walk it's way down the ownership graph. What this attempted to do was build a flat array of IDs which represented explicit and implicit owners (i.e. root + descendants):
declare function hierarchy(doc, owners){
owners = owners || [];
while(doc != null) {
let ownerId = id(doc)
if(ownerId.startsWith('user:')) {
owners.push(ownerId);
} else if(ownerId.startsWith('group:')) {
owners.push(ownerId);
doc.Members.forEach(m => {
let owner = load(m, 'Users') || load(m, 'Groups');
owners = hierarchy(owner, owners);
});
}
}
return owners;
}
I had two issues with this. 1. I don't actually know how to use this in a query lol. I tried to use it as part of the where clause but apparently that's not allowed:
from #all_docs as d
where hierarchy(d) = 'group:my-group-d'
// error: method hierarchy not allowed
Or if I tried anything in the select statement, I got an error that I have exceeded the number of allowed statements.
As a custom index
I tried the same idea through a custom index. Essentially, I tried to create an index that would produce an array of IDs using roughly the same function above, so that I could just query where my id was in that array
map('#all_docs', function(doc) {
function hierarchy(n, graph) {
while(n != null) {
let ownerId = id(n);
if(ownerId.startsWith('user:')) {
graph.push(ownerId);
return graph;
} else if(ownerId.startsWith('group:')){
graph.push(ownerId);
n.Members.forEach(g => {
let owner = load(g, 'Groups') || load(g, 'Users');
hierarchy(owner, graph);
});
return graph;
}
}
}
function distinct(value, index, self){ return self.indexOf(value) === index; }
let ownerGraph = []
if(doc.Owner) {
let owner = load(doc.Owner, 'Groups') || load(doc.Owner, 'Users');
ownerGraph = hierarchy(owner, ownerGraph).filter(distinct);
}
return { Owners: ownerGraph };
})
// error: recursion is not allowed by the javascript host
The problem with this is that I'm getting an error that recursion is not allowed.
So I'm stumped now. Am I going about this wrong? I feel like this could be a subquery of sorts or a filter by function, but I'm not sure how to do that either. Am I going to have to do this in two separate queries (i.e. two round-trips), one to get the IDs and the other to get the docs?
Update 1
I've revised my attempt at the index to the following and I'm not getting the recursion error anymore, but assuming my queries are correct, it's not returning anything
// Entity/ByOwnerGraph
map('#all_docs', function(doc) {
function walkGraph(ownerId) {
let owners = []
let idsToProcess = [ownerId]
while(idsToProcess.length > 0) {
let current = idsToProcess.shift();
if(current.startsWith('user:')){
owners.push(current);
} else if(current.startsWith('group:')) {
owners.push(current);
let group = load(current, 'Groups')
if(!group) { continue; }
idsToProcess.concat(group.Members)
}
}
return owners;
}
let owners = [];
if(doc.Owner) {
owners.concat(walkGraph(doc.Owner))
}
return { Owners: owners };
})
// query (no results)
from index Entity/ByOwnerGraph as x
where x.Owners = "group:my-group-id"
// alternate query (no results)
from index Entity/ByOwnerGraph as x
where x.Owners ALL IN ("group:my-group-id")
I still can't use this approach in a query either as I get the same error that there are too many statements.

Correct search statement when applying filters

I have created a search function for my React-native app, however, I am not quite sure how to create the correct search statement. What I have now is as follows. You can open a filter screen where you can type a few search criteria (for vehicles) so make, model, color, license plate.
After saving the filters you are re-directed to a result page. On this page, I populate a const with Redux data (the vehicle database) and then filter this data before showing it in flatlist.
const vehicles = useSelector(state => state.uploadedVehicles.vehicles)
const filters = props.navigation.getParam('savedFilters')
const filteredVehicles = vehicles.filter(vehicle =>
vehicle.make === filters.makeFilter ||
vehicle.model === filters.modelFilter ||
vehicle.color === filters.licenseplateFilter ||
vehicle
.licenseplate === filters.licenseplateFilter
)
...return Flatlist with filteredVehicles here...
If I set a filter for a particular Make, only vehicles from this make are found. If I set a filter for a model, only vehicles from this model are found. However, if I set a filter for two statements it now shows vehicles with one matching search criteria. If I would search for a blue Dodge I would find vehicles matching the make Dodge, but also every blue vehicle that is uploaded.
How can I expand my search function so It will show vehicles matching 1 filter, but if 2 or more filters are added it will combine these filters to a more specific search function?
I like to take another approach to this, also using Redux. Here I show you an example code:
case SAVE_FILTERS: {
const appliedFilters = state.filters; // Here you have your filters that have to be
initialized in your state. They also have to be turned to true or false but you can
do it in another function (See next one)
// Here we check every condition
const updatedData = state.data.filter(data => {
if (appliedFilters.filter1 && !data.filter1) {
return false;
}
if (appliedFilters.filter2 && !data.filter2) {
return false;
}
if (appliedFilters.filter3 && !data.filter3) {
return false;
} else {
return true;
}
});
// and now you will return an updated array of data only for the applied filters
return {
...state,
displayData: updatedLocations,
};
The trick is to check every single condition inside of the action. In this particular case, we are checking by filters that are true or not, but you can expand to other conditionals.
The flow for the code above is:
If we have a filter applied AND the data HAS that filter, then we pass the conditional. WE do this for all conditionals. If we pass all of them, return true which means it will be added to the display data and the user will see it.
I hope it helps.
Maybe this isn't the most beautiful way of getting the filter to work. But I didn't quite get my filter working with MIPB his response bit it did push me in the right direction.
I am passing the filters in appliedFilters. Then I constantly checking every filter with the part of the vehicle that is filtered for.
Starting with the make of the vehicle. If the make filter is nog set (so "") I just return the vehicles array which contains every vehicle, else I return every vehicle that is matched with the appliedFilters.makeFilters.
This new makeFilterArray is checked with the modelFilter. If this is not set just set it to the makeFilter array to continue checking other filters, if it is set check the makeFilterArray for the matching model.
Maybe not the best/most elegant solution, but with my limited knowledge I got it working! :-)
case FILTER_VEHICLES:
const appliedFilters = action.setFilters;
console.log(appliedFilters)
console.log(appliedFilters.makeFilter)
console.log(appliedFilters.modelFilter)
console.log(appliedFilters.licenseplateFilter)
console.log(appliedFilters.colorFilter)
const makeFilterArray = appliedFilters.makeFilter === "" ? vehicles : state.vehicles.filter(vehicle => vehicle.make === appliedFilters.makeFilter)
const modelFilterArray = appliedFilters.modelFilter === "" ? makeFilterArray : makeFilterArray.filter(vehicle => vehicle.model === appliedFilters.modelFilter)
const licenseplateFilterArray = appliedFilters.licenseplateFilter === "" ? modelFilterArray : modelFilterArray.filter(vehicle => vehicle.licenplate === appliedFilters.licenseplate)
const filteredArray = appliedFilters.colorFilter === "" ? licenseplateFilterArray : licenseplateFilterArray.filter(vehicle => vehicle.color === appliedFilters.color)
// and now you will return an updated array of data only for the applied filters
return {
...state,
filteredVehicles: filteredArray
};

How to create v-autocomplete which first shows items startsWith and then shows items indexOf

I would like to create a vuetify autocomplete with a custom filter that first shows the hits that start with the searchtext and then show the hits that not start with the searchtext, but have the searchtext somewhere in the middle.
I now have a custom filter like this, but this filter is not prioritizing words that start with the searchtext:
customFilter(item, queryText) {
const textOne = item.description.toLowerCase();
const textTwo = item.code.toLowerCase();
const searchText = queryText.toLowerCase();
return (
textOne.indexOf(searchText) > -1 || textTwo.indexOf(searchText) > -1
);
}
},
Codepen (Type 'ma' for example)
I believe you need to sort it manually, filter returns only true/false whether item is a match.
// https://stackoverflow.com/a/36114029/1981247
var _sortByTerm = function (data, term) {
return data.sort(function (a, b) {
// cast to lowercase
return a.toLowerCase().indexOf(term) < b.toLowerCase().indexOf(term) ? -1 : 1;
});
};
Then pass sorted array to items prop
<v-autocomplete :items="computedItems"
...
computed: {
computedItems() {
return _sortByTerm(this.states, this.search.toLowerCase())
},
},
Note this is just to get you started, and you might need to change code a bit according to the data (and filters) you are using, e.g. _sortByTerm works only on array of strings, but in the link there is a solution for sorting arrays of objects also.

how to use lodash filter function using variable

I am using lodash in one of my projects to achieve filter. My requirement is we have different SELECT options that are generated dynamically. And these are populated with json.
So my filter function that I need should be generic. For example if there are 3 drop downs.
dropdown1. populated with values whose json_property is ABC_CODE="002"
dropdown2. populated with values whose json_property is xyz_CODE="002"
dropdown2 values should change based on dropdown1 selection
I have a masterdata list, which tells this information.
The loadash _.filter function should use varaibles. Because this filter should be used dynamically for different select options.
ex:
var a=_.filter($scope.masterData, function(e){
return _.indexOf(v, e.ABC_CODE) != -1;
});
console.log(a); //returns array of objects
I get the values.
How can I replace ABC_CODE from a javascript variable. like e.tempVar where tempVar is ABC_CODE
use bracket notation
var a = _.filter($scope.masterData, function(e) {
var key = ABC_CODE;
return _.indexOf(v, e[key]) != -1;
});
console.log(a); //returns array of objects

"update" query - error invalid input synatx for integer: "{39}" - postgresql

I'm using node js 0.10.12 to perform querys to postgreSQL 9.1.
I get the error error invalid input synatx for integer: "{39}" (39 is an example number) when I try to perform an update query
I cannot see what is going wrong. Any advise?
Here is my code (snippets) in the front-end
//this is global
var gid=0;
//set websockets to search - works fine
var sd = new WebSocket("ws://localhost:0000");
sd.onmessage = function (evt)
{
//get data, parse it, because there is more than one vars, pass id to gid
var received_msg = evt.data;
var packet = JSON.parse(received_msg);
var tid = packet['tid'];
gid=tid;
}
//when user clicks button, set websockets to send id and other data, to perform update query
var sa = new WebSocket("ws://localhost:0000");
sa.onopen = function(){
sa.send(JSON.stringify({
command:'typesave',
indi:gid,
name:document.getElementById("typename").value,
}));
sa.onmessage = function (evt) {
alert("Saved");
sa.close;
gid=0;//make gid 0 again, for re-use
}
And the back -end (query)
var query=client.query("UPDATE type SET t_name=$1,t_color=$2 WHERE t_id = $3 ",[name, color, indi])
query.on("row", function (row, result) {
result.addRow(row);
});
query.on("end", function (result) {
connection.send("o");
client.end();
});
Why this not work and the number does not get recognized?
Thanks in advance
As one would expect from the initial problem, your database driver is sending in an integer array of one member into a field for an integer. PostgreSQL rightly rejects the data and return an error. '{39}' in PostgreSQL terms is exactly equivalent to ARRAY[39] using an array constructor and [39] in JSON.
Now, obviously you can just change your query call to pull the first item out of the JSON array. and send that instead of the whole array, but I would be worried about what happens if things change and you get multiple values. You may want to look at separating that logic out for this data structure.