I'm trying to perform a filter by pattern over a Firestore collection. For exemple, in my Firestore database I have a brand called adidas. The user would have an search input, where typing "adi", "adid", "adida" or "adidas" returns the adidas document. I pointed out several solutions to do this :
1. Get all documents and perform a front-end filter
var brands = db.collection("brands");
filteredBrands = brands.filter((br) => br.name.includes("pattern"));
This solution is obviously not an option due to the Firestore pricing. Moreover it could be quite long to perform the request if the number of documents is high.
2. Use of Elasticsearch or Algolia
This could be interesting. However I think this is a bit overkill to add these solutions' support for only a pattern search, and also this can quickly become expensive.
3. Custom searchName field at object creation
So I had this solution : at document creation, create a field with an array of possible search patterns:
{
...
"name":"adidas",
"searchNames":[
"adi",
"adida",
"adidas"
],
...
}
so that the document could be accessed with :
filteredBrands = db.collection("brands").where("searchNames", "array-contains", "pattern");
So I had several questions:
What do you think about the pertinence and the efficiency of this 3rd solution? How far do you think this could be better than using a third party solution as Elasticsearch or Algolia?
Do you have any other idea for performing pattern filter over a firestore collection?
IMHO, the first solution is definitely not an option. Downloading an entire collection to search for fields client-side isn't practical at all and is also very costly.
The second option is the best option considering the fact that will help you enable full-text search in your entire Cloud Firestore database. It's up to you to decide if it is worth using it or not.
What do you think about the pertinence and the efficiency of this 3rd solution?
Regarding the third solution, it might work but it implies that you create an array of possible search patterns even if the brand name is very long. As I see in your schema, you are adding the possible search patterns starting from the 3rd letter, which means that if someone is searching for ad, no result will be found. The downside of this solution is the fact that if you have a brand named Asics Tiger and the user is searching for Tig or Tige, you'll end up having again no results.
Do you have any other ideas for performing pattern filters over a Firestore collection?
If you are interested to get results only from a single word and using as a pattern the staring letters of the brand, I recommend you a better solution which is using a query that looks like this:
var brands = db.collection("brands");
brands.orderBy("name").startAt(searchName).endAt(searchName + "\uf8ff")
In this case, a search like a or ad will work perfectly fine. Besides that, there will be no need to create any other arrays. So there will be less document writing.
I have also written an article called:
How to filter Firestore data cheaper?
That might also help.
Related
I'm messing around with Cloud Firestore. Trying to decide whether I should use it for my next project.
I would like to make a nested query, but all the tutorials and examples I found in the official documentation only query objects which are 2 levels deep and most of the time direct key/id calling.
I need something which is I believe called "nested query" I may be wrong on that one though, maybe it is not the correct phrase for such a thing in NoSQL which I just started to learn.
This is a skeleton/pilot app for a game where users can create characters. and I would like to query whether a character's name is already taken or not.
Here is my simple DB structure:
The main collection is named "users"
In "users" I have user documents.
In each user document, I have a collection named "characters"
In "characters" I have character documents.
In each character document there are two fields, name and level.
I tried it various ways with queries and the closest thing I could get was iterating through the whole thing which I believe is not the perfect solution.
Can somebody please help me to write an efficient nested query whether "Example Name" is already an existing character in the DB and tell me what is the correct way when you want to write like "infinitely deep" nested queries?
If each user document contains a sub-collection that has the same ("characters") name, then I think you are looking for a collection group query. So a query should look like this:
val queryByName = db.collectionGroup("characters").whereEqualTo("name", "Adam");
Don't also forget to create an index.
Besides that, Firestore is as fast as it is at level 1 is also at level 100. So no worries.
I understand that using .indexOn is better for performance but to understand further here's my question whether or not I should design my tree nodes differently.
Let's say I want to search for a name and see if it exists. I could have:
names
jack : true
john: true
or
people
UID1
name : jack
age : 10
If I had .indexOn at "name" in the "people" node. Would it have the same cost/performance as the first tree? The reason I ask is because I want to avoid making as many tree nodes as possible.
The cost for reading from the Firebase Realtime Database is based on the bandwidth that is transferred. In the first JSON, you'd only be reading true, while in the second snippet you'd end up reading the entire UID1 node. So that would be (marginally) more expensive.
If on the other hand, you also look up the user profile after reading jack: true from the first JSON, then that approach probably reads more data and would thus be (again: marginally) more expensive.
In the first JSON snippet, you can look jack directly based on their path, without needing a query. A direct lookup is the fastest way to read a node.
In the second JSON snippet you're going to need a query. When you have only a few users, the performance is going to be quite similar. But as the number of users grows, this query will start taking more time (even when you've defined an index to ensure it happens server-side).
But this performance difference won't be very noticeable until you have hundreds of thousands of users. Before that it is likely dwarfed by the impact of network performance.
I have a set of collections in Firestore that each has n different documents, each one with its particularity, in my application I have a menu that the user can search for a specific document and I must search for that document.
However, the problem lies in this case, I do not know when searching for which collection to look for the document in, so far I am searching all collections to find the document the user wants in himself, I wonder if there is any way to search for a document without knowing exactly what collection it is in but in a way that I don't have to go through the database completely.
Currently I do something like this:
Search Lot 01 collection:
...>search returned the document: then cancel the searches.
>search did not return the document, so proceed with the search in Lot 02 ...
and so on until you find the document...
In SQL I would basically have one of these fields as the primary key and search for it, but Firestore is NoSQL
if there is any way to search for a document without knowing exactly what collection it is in
That's not possible. All Firestore queries require the name of a single collection (or collection group, where all the subcollections have the same name).
With Firestore, if you want a set of documents to be searchable, then they have to be in a collection with a name that you know ahead of time. You might have to duplicate data into this known collection to solve this particular problem. Or, find a database that does allow universal searching, like some full text search engines allow.
After reading the Firebase documentation, I understood that the logical structure in NoSql is totally different than in SQlite. I can do basic searches ordered with:
orderByChild(), orderByKey() and orderByValue() and filtered with
startAt(), endAt() and equalTo().
I'm building an app similar to the Bible. The app project requires that there be search filters, such as:
"Starting with": ex: Excelent
"Containing": ex: Exchent
"All Words": ex: Jesus is the same
Exact Phrase: ex: Jesus is the same
The Firebase Realtime Database function is excellent for fixing typing errors or missing text, once the broadcast changes on all devices, this is undoubtedly something phenomenal.
Considering the image:
See the structure of JSON in firebase
Is it possible to do these search filters with Firebase?
What is the best way to build these filters using Firebase's own API?
Would I have to use these same filters with the offline data?
There is no such a think as a LIKE query equivalent in Firebase. You could create an extra node like this:
"common_queries": {
"jesus": {
"0": "awdawdn",
"1": "oiefpowmfpowmf"
},
"eggcelent":{
"0": "oiefpowmfpowmf"
}
}
Then you can query trying to hit a key, and the results are the reference to the keys of other nodes.
There is another alternative wich involves using the startAt() method and endAt(), by adding the last text searchable value, here is a great video for it
I think Firebase is a tool in your toolbelt, in this case, is not the most suitable tool. Don't drill a hole with a circular saw, just use a drill.
No, it's not possible. Unfortunately, Firebase does not provide a text search mechanism as you described in your post and as far as i know, there is no other database which provides something like this by default.
I'm having a bit of trouble with a Firebase Query. I want to query for objects, where the objects child value contains a certain string. So far I have something that looks like this:
Firebase *ref = [[Firebase alloc] initWithUrl:#"https://dinosaur-facts.firebaseio.com/dinosaurs"];
[[[[ref queryOrderedByKey] queryStartingAtValue:#"b"] queryEndingAtValue:#"b~"]
observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
NSLog(#"%#", snapshot.key);
}];
But that only gives objects that have a starting value of "b". I want objects that contains the string "b". How do I do that?
There are no contains or fuzzy matching methods in the query API, which you have probably already guessed if you've scanned the API and the guide on queries.
Not only has this subject been discussed ad nauseam on SO [1] [2] [3] [4] [5], but I've touched several times on why one should use a real search engine, instead of attempting this sort of half-hearted search approach.
There is a reason it's often easier to Google a website to find results than to use the built-in search, and this is a primary component of that failure.
With all of that said, the answer to your question of how to do this manually, since there is no built-in contains, is to set up a server-side process that loads/streams data into memory and does manual searching of the contents, preferably with some sort of caching.
But honestly, ElasticSearch is faster and simpler, and more efficient here. Since that's a vast topic, I'll defer you to the blog post on this subject.