OR query in rethink - arrays

Is it possible to do OR search on values of array in Rethink.
Eg: I have table called "post" with field "tags" which is an array. I want to do an OR search on values of tags.
post1 {
tags : ["young","agreesive"]
}
post2 {
tags : ["cricket","India"]
}
Give me all posts which contains tags "young" or "cricket" should return be both the posts.

As mlucy said, you can use filter in conjunction with or and contains to get all documents with a specific tag.
If you have an array of tags, you can do the following too:
var tags = ["young", "cricket"];
r.table('posts').filter(function (row) {
return r.expr(tags).contains(function (value) {
return row("tags").contains(value)
});
})
This is more easily extensible than using or.
Multi Index
You can also create a multi-index for that property. Multi-indexes let you lookup data by any of the values in an array. So, for example:
r.table("posts").indexCreate("tags", {multi: true})
r.table("posts").getAll("young", "cricket", {index: "tags"})
This query would get all the documents with the "young" and "cricket" tag, and it's more performant and cleaner than using the nested contains.

You can do that with or and contains:
r.table('posts').filter(function(row) {
return row('tags').contains('young').or(row('tags').contains('cricket'));
})

Related

How to search and filter on an array in Ionic v5?

currently I'm trying to filter and search an array in Ionic v5. But I don't know how to combine these two criteria.
I have a page (room-overview), which displays all objects of a room-array. I get these objects from a "data service", which reads a JSON file.
Part of the room-overview.ts-file:
ionViewDidEnter() {
this.setSearchedItems('');
this.searchControl.valueChanges
.pipe(debounceTime(300))
.subscribe(search => {
this.searching = false;
this.setSearchedItems(search);
});
}
onSearchInput() {
this.searching = true;
}
setSearchedItems(searchTerm) {
this.rooms = this.dataService.searchItems(searchTerm);
}
On the room-overview page, there is a search bar, which can be used to search the individual objects. This search bar calls the onSearchInput()-method.
<ion-searchbar [formControl]="searchControl (ionChange)="onSearchInput()">
For that, I have a filter/search-service that gives me all objects which fits the search term. "items" is an array of all room-objects.
searchItems(searchTerm) {
return this.items.filter(item => {
return item.name.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1;
});
}
Besides the search, it should be possible to filter by certain criteria (for example, whether a room is in a certain building or not). This filter possibility is solved via a modal page that passes the values to the room-overview page when it will be closed.
Either the search or the filtering can be done individually, but I do not know how to combine both. I think the "searchItem()"-method should not only filter on the room-object array. It should be able to filter before and use only the filtered array.
I hope someone can help me :-)
Perhaps something like this?
searchAndFilterItems(searchTerm) {
const filteredItems = this.items.filter(item => {
// Apply filters
});
return filteredItems.filter(item => {
return filteredItems.name.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1;
});
}

Is it possible to filter Firestore data on multiple, user selected values in Angular

I'm essentially trying to build a product filter where the user can select (or not select e.g. they aren't required) from any of the filter options.
My firestore is setup as:
product
{
colour: "white"
brand: "a brand"
}
Currently I can filter on say 'colour' with this code:
filterProducts(value: string){
this.filteredProducts = this.db.collection('products', ref => ref.where('colour', '==', value)).valueChanges();
}
How can I adapt the above to be able to filter on either colour, brand or both? Is this even possible?
If you're asking whether you can query on multiple fields, the answer is "yes". For example to filter on brand and color:
ref.where('colour', '==', 'white').where('brand', '==', 'a brand')
For more on this see the Firebase documentation on filtering data and compound queries.
You'll of course need to pass both values into your filterProducts method in order to be able to use them.
If you only want to add a condition when the user has given a value for that filter, you'd do something like this:
ref = firebase.firestore.collection(...); // whatever you already have
if (colourValue) {
ref = ref.where('colour', '==', colourValue);
}
if (brandValue) {
ref = ref.where('brand', '==', brandValue);
}

AngularJS, accessing ngRepeat values in filter predicate

My best attempts at finding a solution to this have come up empty. Basically I want to do something like this in my html:
<div data-ng-repeat="tag in allTags">
<h3>{{tag}}</h3>
<uib-accordion>
<div uib-accordion-group data-ng-repeat="item in displayItems | filter: tagFilter: tag">
tagFilter looks like this:
$scope.tagFilter = function(item, tag) {
if(item.tags.indexOf(tag) === -1) {
return false;
}
return true;
}
Each item in displayItems is an object that has an array of tags, so display items looks something like this:
[
{ title: "Item 1 Title", body: "Some escaped HTML Content", tags: ["tag1", "tag2", "tag3"]},
{ title: "Item 2 Title", body: "Some escaped HTML Content", tags: ["tag2", "tag4"] }
]
and I want it to appear under all headings to which it belongs. The problem is I can't figure out how to properly pass the value of 'tag' to tagFilter. In the code above the parameter tag in codeFilter is just equal to 0 no matter what.
The problem here is actually in the semantics of the Filter syntax. More specifically, the syntax you're using above is for when you're defining an Angular Filter using the ngApp.filter(...) syntax... i.e., a filter that's registered for the entire application and can be used anywhere. In that scenario the 3rd parameter in your filter statement is the value you want to pass to the registered filter.
In your case, you're defining a filter function inside your controller which changes how the filter works. Specifically, you cannot pass dynamic values to a filter function inside a controller. When you use a function as the filter expression, it has the following signature:
function(value, index, array) {}
and then gets called in the filter statement just by the function name, so:
array|filter:filterfunction - with no params or parenthesis.
value is the value of the current item (in the array) being filtered, index is the index of that item in the array, and array is the whole array being filtered. You cannot "pass" a value to this expression, but you can use a controller or scope variable if it applies. In your case it doesn't because the value you want to filter on is inside a repeater.
To achieve what you want, you need to make your $scope.tagFilter into an actual Angular Filter, like so:
ngApp.filter('tagFilter', function($filter)
{
return function(items, searchValue)
{
// initialize array to return
var filtered = [];
angular.forEach(items, function(obj)
{
// use filter to find matching tags (3rd param means EXACT search - set to False for wildcard match)
var objFilter = ($filter("filter")(obj.tags, searchValue, true))[0];
// If a matching tag was found, add it to the filtered array
if (objFilter) filtered.push(obj);
});
return filtered;
};
});
The above assumes you've saved your angular.module(...) bootstrap to a variable named ngApp. Once this filter is registered, your current filter syntax should work as expected!
Assuming displayItems is an array,
<div uib-accordion-group data-ng-repeat="item in displayItems.filter(tagFilter(tag))" >
should do the trick.
Figured out a way to do this based on this blog post: https://toddmotto.com/everything-about-custom-filters-in-angular-js/
Basically I had to create my own custom filter rather than using angulars predicate filter
The Javascript:
ng.module('faq').filter(
'tagFilter', function() {
return function(items, tag) {
return items.filter(function(item) {
if(item.tags.indexOf(tag) === -1) {
return false;
}
return true;
});
}
}
)
The HTML:
<div uib-accordion-group data-ng-repeat="item in displayItems | tagFilter: tag">
Still don't know why the original version was not working, so if anyone can answer that 10 points to them.

$.grep to return property after match

I couldn't find any instances where this was being done so I'm asking you brainy people out there if there's a nice easy way to do what I'm wanting.
Trying to map two arrays together. One array has a list of the IDs (Foos), and the other array has all the properties (bars) for those IDs. Want to keep everything in my angular controller.
Here's a snippet. I'm trying to match on ID and map into the Name property.
$scope.Foos = $.map($scope.Foos, function (foo) {
return {
ID: foo.ID,
Name: $.grep($scope.bars, function(b){
return b.ID === foo.ID;
}).Name,
Property: $.grep($scope.bars, function(b){
return b.ID === foo.ID;
}).Property
};
});
What I understand is that $.grep will return the object based on the criteria, can I then call properties of that returned object?
Update:
Foos is ID (guid)
Bars is ID(guid), Name & Property
$.grep returns an array, not an object, so to do what you are wanting you would need to do something like:
Name: $.grep($scope.bars, function(b){
return b.ID === foo.ID;
})[0].Name
The problem here however is if there is no match , $.grep will return an empty array and you will end up throwing an error trying to get the first element from that empty array.
You really should look the properties up first, not while trying to build a more complex object
Something like:
$scope.Foos = $.map($scope.Foos, function (foo) {
// first filter the array
var bars = $.grep($scope.bars, function (b) {
return b.ID === foo.ID;
});
// now test we have result, if not make it ... empty string???
var name = bars.length ? bars[0].Name : '';
// do similar for `Property`
return {
ID: foo.ID,
Name: name,
......
};
});
This could also be modified to have some utility functions like getNameFromBars() and put the $.grep in there and return value found or the default.
If you wanted to get rid of jQuery you could use Array.prototype.map() and Array.prototype.filter() to replace $.map and $.grep.
Also $filter could be used.

Backbone JS filters form

I have a UI with a form that has dropdowns andcheckboxes in order to filter the results returned from the server.
I wonder if I have to create a Model in order to keep the current settings available or just get the vals with jquery and pass them to the Collections fetch.
What would be better?
That dependes how much you want to invest in design, or you just can live with a more pragmatic approach.
If you run for the design solution we can say that there is not a Collection of results what we are playing with here. It is a FilterSearch model, and every time we are sending the filter params to the server what we are doing is creating an instance of FilterSearch. Let's say:
POST http://myapp.com/filter_searchs?field1=value1&field2=value2
The server will take this request and will return the array of results. Let's say:
{
"field1": "value1",
"field2": "value2",
"results": [ "result1", "result2" ]
}
The Backbone FilterSearch model will be updated with the info responded by the server:
var myFilterSearch = App.FilterSearch.new({ field1: "value1", field2: "value2" });
myFilterSearch.save({ wait:true });
And from there we can create our results Collection:
var myResults = App.Results.new( myFilterSearch.get( "results" ) );
(All code is simplified and not tested)
Another solution can be to store the filter fields into the Collection it self.
App.Results = Backbone.Collection.extend({
url: function() {
return "/results?field1=" + this.field1 + "&field2=" + this.field2 );
}
});
var myResults = App.Results.new({ field1: "value1", field2: "value2" });
myResults.fetch();
This approach is interesting because you can update the results just modifying the filter fields in the Collection and call to .fetch(), all the references to the Collection will remain.
(All code is simplified and not tested)
For filtering collection using backbone the best approach is to fetch the collection and the return a subset filtered collection this will also make you code more reusable
To make the filter you should have a filtered function
var yourCollection = Backbone.Collection.extend ({
filtered : function () {
I suggest to use UnderScore filter which will return true for valid and false for invalid where true is what you are looking for. use this.models to get the current collection models use model.get( '' ) to get the element you want to check for
for example you may have a check box which shows a specific category
var results = _.filter( this.models, function ( model ) {
if ( item.get('category') === 'y' )
return true ;
return false ;
});
You may keep filtering the result with all you dropdown and checkboxes
Then use underscore map your results and transform it to JSON like
results = _.map( results, function( model ) { return model.toJSON() } );
Finally returning a new backbone collection with only results
return new Backbone.Collection( results ) ;
Optionally if you don't want to keep all the data in the collection but just the filtered one you could reset the collection and skip the above return like
this.reset( results ) ;
View : Here your ui data requested you should call the filtered function after passing the ui for values using jquery

Resources