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.
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 am starting with Firebase and want to know what are the most effective ways to structure data
Let's take the example of a simple social media app where only photos can be shared (like the beginnings of Instagram).
user upload a photo with some meta data (Description)
(Home Feed) the users (followers) will see the post in a chronological way
and offcource there will be other functionality like (liking the post , saving it , commenting)
searching and following users
notification about likes and comments
search in comments
what could be a good structure for storing the data and good effcient way to get data ASAP
I'll go ahead and leave an answer for how I would approach this. My answer will be geared more towards Firestore even though the question is marked as Realtime Database. There are multiple ways to structure the data. This is the general structure I would use given your example:
users
- name
- timestamp
posts
- imageURL
- description
- timestamp
- likeCount
- commentCount
posts/comments //subcollection
- userID
- comment
- timestamp
posts/likes //subcollection
- userID
- timestamp
savedposts
- postID
- userID
followers
- userID
- followedID
Some additional notes:
Image Upload
The best option here is to upload the images to cloud storage and utilize a cloud function to generate a public URL and save it to the post document.
Comment / User Search
As stated in my comment, Firebase does not have a great solution for text based searches. The solution I utilized in my project was to utilize a cloud function to keep an Algolia index in sync with my users collection. I then offload the user search to them through a callable cloud function - though you could utilize the Algolia client SDK directly in your app if you wanted. In your scenario, you would also have to keep all of your comments in sync as well. Algolia isn't a cheap service, so I would look into the pros / cons of using the other options listed in the docs.
Document IDs
I generally let Firestore auto ID the documents, but here I would make some exceptions. For the savedposts and followers collections I would utilize a (manual) compound ID of {userID}{postID} and {userID}{followedID} respectively. It allows you to perform simple actions of unliking and unfollowing without querying for the document first. Ex) firestore().collection('postsaves').doc(`${userID}${postID}`).delete()
Final Thoughts
You mention maybe moving to AWS. I have worked much more in Firebase than in AWS, but I have done both. In my opinion, Firebase is unmatched in both usability and documentation. There are some compromises in terms of functionality and fine tuning but I recommend sticking with Firebase if the lack of text searching is the only hurdle.
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.
I have the structure below. A document in Firebase with the types Map, int and String. On the application screen, I have a specific widget to add a user and I have another widget to add the Address Map separately. So I thought of the following solution: I create an Address class with the attributes I need (city, street) and use those attributes to be able to save what the user types in the form of the screen. Then I do the conversion to map and save this information inside the user as an update.
Is this a good solution or is there a simpler way? Is it more interesting to have a sub-collection instead of a Map of address?
Don't do what seems more "interesting". Do what satisfies the needs of the queries you need to perform on this data. This is the only real rule of data modeling for Firestore, because if you make a decision that doesn't work for the use cases you expect, then you will have a lot of work to do to change it.
I don't see anything here that needs a subcollection.
Do what your application requires. If you feel your application will need a certain structure of data going forward then try to plan for this. But don't over-engineer too early in the development cycle.
I am currently using api.ai , to create agent to perform specific tasks, but one question i don't have answer to is , can i make it learn something while chatting , mean that i speak my name is 'John Cena' and she should store it and then whenever i ask her again bot should answer me that. i know there is a way to do it by logging into api.ai web and manually add entries , but it will not help, is there any work around programmatically or automatically ? the file i've been using to practice is given in github . and here is working DEMO
You basically need for your bot to "learn" facts. There are many different ways to achieve this, but recently the most common way is to arrange knowledge into Semantic "Triples" and store the knowledge into a Graph repository (like Neo4j, Titan, Spark Graph, etc). In your example, "my name is John Cena" would translate into a Triple like ("anubava","Name","John Cena"). That way, the next time you are logged in as anubhava and ask "What is my name?", it would translate into a Graph search that will return "John Cena". A word of caution, achieving this is not trivial and would require some significant amount of fine tuning. For more info, you can check here and here.
Finally, most complete solutions (that I know of), are Server Side solutions. If you want for the whole knowledge base to reside in your mobile device, you could probably use the resources there as inspiration, and build your own Linked Data repository using an embedded database.
Hope this helps. Good luck.
To store and recall the user's name, you'll need to set up a webhook with some basic data persistence capabilities. Any database or key-value store would work fine.
Here's the breakdown:
Implement webhook fulfillment for the intent that captures the user's name. The webhook should store the name along with a unique, identifying ID that you should supply from your front-end in either the sessionId or as a context parameter in your call to /query.
Implement webhook fulfillment for the intent that reads the user's name. The webhook should look up the name by ID and return a response that tells the user their name.
The high-level docs for writing a fulfillment webhook are here:
https://docs.api.ai/docs/webhook