Firestore create compound query from array - javascript

I'm trying to create a compound query to do a range query.
let query;
category.queryParams.query.fieldFilters.forEach(function(fieldFilter) {
query = collection.where(fieldFilter.field, filterOperationString(fieldFilter.filterType), fieldFilter.filterValue);
});
But it's not giving me the results I want.
I'm having a feeling that the query needs to be created chained like collection.where().where()
If that is the case, how can I transform the contents of my array using that syntax?

From my understanding, you have an array named fieldFilters that contains multiple objects with a field attribute (e.g. 'price'), a filterType attribute (e.g. '>') and a filterValue attribute (e.g. 50). If you are trying to do multiple range queries on different fields, then this will not work as stated in the documentation https://firebase.google.com/docs/firestore/query-data/queries#compound_queries. Solutions do exist for this problem, I suggest you read Frank van Puffelen response to the following question: Firestore multiple range query.

Solved it with this code:
let query;
category.queryParams.query.fieldFilters.forEach(function(fieldFilter) {
if (typeof query === "undefined") {
query = collection.where(fieldFilter.field, filterOperationString(fieldFilter.filterType), fieldFilter.filterValue);
} else {
query = query.where(fieldFilter.field, filterOperationString(fieldFilter.filterType), fieldFilter.filterValue);
}
});

Related

Using equalTo() function in Firebase Database JavaScript v9

I am trying to use the equalTo function in the Firebase Database JavaScript v9 SDK. It's not very well documented like V8 is so can't figure out how to do what I want to do.
I want to filter results by the type field. My parent field is request-log with child elements like below.
{"backtrace":false,"message":false,"organisationID":"Empty","postData":false,"referrer":"Empty","remoteIP":"0.0.0.0","requestMethod":"POST","time":1630129562,"type":"Error","url":"Empty","user":{"email":"Empty","firstName":"George","id":37,"lastName":"Bates"},"userAgent":"Empty"}
I am trying the following, but not getting any results when loaded:
const readNewLogEntries = query(child(ref(db), 'request-log'), equalTo('Error', 'type'));
I have also tried this, as the reference docs say for the 2nd argument in the equalTo() function
This argument is only allowed if ordering by child, value, or priority.
But this isn't working either
const readNewLogEntries = query(child(ref(db), 'request-log'), orderByChild('type'), equalTo('Request', 'type'));
EDIT: Screenshot of DB
Remove the second parameter from equalTo().
The optional key argument can be used to further limit the range of the query. If it is specified, then children that have exactly the specified value must also have exactly the specified key as their key name. This can be used to filter result sets with many matches for the same value.
const getData = async () => {
const readNewLogEntries = await get(
query(ref(db, "request-log"), orderByChild("type"), equalTo("Request"))
// Filters where "type" is equal to "Request". Single arg here ⬆
);
console.log(readNewLogEntries.val())
return readNewLogEntries.val();
};
You can read more about the parameters in the documentation

Best way to remove empty query strings from an API request

In my react app I am tasked with sending multiple GET requests, sometimes with some optional filter params attached. Additionally I'm storing the params in my redux store so that they are able to stack on subsequent requests. Here's the problem: There are times when I'll clear the values of a param but since their keys are still saved to my store I'll get requests sent out like this:
/restaurants/?search=&state_id=2
Notice how the search param value is empty (as expected). I was wondering what would be the best approach in removing these type of lingering params? I looked into lodash's _.omitBy combined with _.isEmpty but this throws a sort of false positive in dealing with numeric values like pagination.
_.omitBy(params, ._isEmpty);
I didn't think that providing how exactly the params are via react/redux was necessary stored but am happy to provide it if it helps.
Note: I'm using axios and passing my params in as an object as opposed to a string:
axios.get('restaurants', {
params
});
Considering your params are stored in an object (as you mentioned in your latest edit), you can just remove properties containing empty strings:
const params = {
search: "",
state_id: 2
};
for (const key of Object.keys(params)) {
if (params[key] === "") {
delete params[key];
}
}
console.info(params);
This alternative has the advantage of being short and easy to maintain.
But for those with a string containing all params already serialized, it's easy to do using regular expressions:
function removeEmptyParams(query) {
return query.replace(/[^=&]+=(?:&|$)/g, "");
}
const testQuery = "f=1&search=&state_id=2&foo=&bar=12";
console.info(removeEmptyParams(testQuery));
Also very simple and easy to maintain.
The best and easiest way is to use a Spread Object literal on every optional param,
like this
params:{
...( CONDITION && {param_key: param_value}),
...( this.state_id != null && {state_id: this.state_id})
}
If condition is TRUE, the encapsulated key:value pair will be unwrapped, if condition is false , there will be no empty value or key.
You might need to parse that manually. Split on the & then split on the = and check if there's a value based on the length of the split - remove accordingly from there. If you're comfortable with regex you can check if there are values after the = instead of splitting.
This solution is a little crude, but it works. Let's assume your query params are stored in a Map, something like:
const params = {
foo: 'bar',
bang: 0,
buzz: '' // this value has been removed from your store
}
You could create an array of keys from your params Map, filter out the items that don't have a value and then join them all back together as query params.
const queryString = Object.keys(params).map(filter => {
if (params[filter] || Number.isInteger(params[filter])) {
return `${filter}=${params[filter]}`;
}
return null;
}).filter(item => item).join('&');
Which would result in foo=bar&bang=0

Building a progressive query in Mongoose based on user input

I'm writing a simple REST API that is basically just a wrapper around a Mongo DB. I usually like to use the following query params for controlling the query (using appropriate safeguards, of course).
_filter=<field_a>:<value_a>,<field_b><value_b>
some values can be prepended with < or > for integer greater-than/less-than comparison
_sort=<field_c>:asc,<field_d>:desc
_fields=<field_a>,<field_b>,<field_c>
_skip=<num>
_limit=<num>
Anyway, the implementation details on these are not that important, just to show that there's a number of different ways we want to affect the query.
So, I coded the 'filter' section something like this (snipping out many of the validation parts, just to get to point):
case "filter":
var filters = req.directives[k].split(',');
var filterObj = {};
for(var f in filters) {
// field validation happens here...
splitFields = filters[f].split(':');
if (/^ *>/.test(splitFields[1])) {
filterObj[splitFields[0]] = {$gt: parseInt(splitFields[1].replace(/^ *>/, ''), 10)};
}
else if (/^ *</.test(splitFields[1])) {
filterObj[splitFields[0]] = {$lt: parseInt(splitFields[1].replace(/^ *</, ''), 10)};
}
else {
filterObj[splitFields[0]] = splitFields[1];
}
}
req.directives.filter = filterObj;
break;
// Same for sort, fields, etc...
So, by the end, I have an object to pass into .find(). The issue I'm having, though, is that the $gt gets changed into '$gt' as soon as it's saved as a JS object key.
Does this look like a reasonable way to go about this? How do I get around mongoose wanting keys like $gt or $lt, and Javascript wanting to quote them?

Parse.com : Query Max Value of Column in JS API

If in sql, we can get it with:
select Max(Column_name) from Table_name
but still can't find simple way to get Max value of Column in Parse.com JS API.
Please explain me how to get Max Value of Column in JS API?
The best way to do this is to use Parse.Query (api) and order by descending, then obtain the first item in the result.
Edit:
Maybe, it's not a good idea to use order by in the situation that there are thousands(or even more) items as it's time consuming(complexity at least O(nlogn)). An alternative is to write a function of your own to choose the maximum value yourself with complexity of O(n).
Write a query for descending order and fetch the first object out of it. You will have the max value of the column there.
var query = new Parse.Query("something");
query.descending("column_name");
query.first({
success: function(result){
var max = result.get("column_name");
},
error: function(){
},
})
I am not sure if you can do it directly with a max function. You can create your own max function by doing a query to get all entries from that column and sorting them in descending order. There are APIs for this. Then choose the first value from the sorted list.
You can basically follow the same pattern from all other queries:
// Query for ID
ParseQuery<ParseObject> query = ParseQuery.getQuery("Table_Name");
// Condition
query.orderByDescending("ID");
// First object will be retrieved, this will be the max_value
query.getFirstInBackground(new GetCallback<ParseObject>() {
public void done(ParseObject object, ParseException e) {
if (object == null) {
Log.d("score", "The getFirst request failed.");
} else {
Log.d("score", "Retrieved the object.");
}
Now you can get the value using something like:
String mensagem = object.getString("ID");
Hopefully this will help you!

backbone find on collection

I know the method to find a model in a collection from a single attribute,
var musketeers = friends.where({job: "Musketeer"});
but if i want contemporary find by two attribute and return a single result?
My idea is to find once a time the single attributes and after connect the two result:
var name = friends.where({name: "stefano"});
var surname = friends.where({surname: "maglione"});
and after connect the results.
I need because i'm coding a search function to find people based on name and surname.
But there is another problem:if user insert before name and after surname or vice versa?
You could also use the filter method to achieve it
var musketeers = friends.filter(function(friend) {
return friend.get('job') === stefano' && friend.get('surname') === 'maglione';
});
Collection.where in fact accepts multiple attributes:
where collection.where(attributes)
Return an array of all the models in a collection that match the passed attributes.
Useful for simple cases of filter.
You could write your request as
var found = friends.where({
name: "stefano",
surname: "maglione"
});
See http://jsfiddle.net/nikoshr/kuLYE/ for a demo

Categories

Resources