Do a research in a Firestore document - flutter

In my collection "users", each user is defined by their name, list of hobbies, and skills:
Structure of a document in "users":
name : "Name"
hobbies: ["hobby1","hobby2","hobby3"]
skills: ["skill1","skill2","skill3"]
What I want is: Get all documents in the collection where one of those fields contains a specific word. The problem is that currently I get all documents and then I do a loop to retain the matching documents. But I would prefer to do a query instead (reads are expensive). So I was thinking to reorganize the document like this:
New structure:
data: ["Name","hobby1","hobby2","hobby3",skill1","skill2","skill3"]
So I could do a query with "where" and "array-contains". What do you think? Isn't it strange?

If you want to have a OR statement between the hobbies and skills then you can't use a query that uses array-contains. As stated on this documentation:
You can use at most one array-contains clause per query. You can't combine array-contains with array-contains-any.
What I would suggest is to combine the skills and hobbies into one.:
e.g.:
name : "Name"
skillsandhobbies : ["Hobby1", "Hobby2", "Hobby3", "Skill1", "Skill2", "Skill3"]
Then you can use this sample query to get all the documents that have hobbies or skills that contain a specific word:
const q = query(collection(db, "users"), where("skillsandhobbies", "array-contains", "specific-word"));

As I understood from your comments, you basically need to perform a successive search. You need to search the hobbies array for a particular word, and if you don't get any results, you need to perform another search, in the skills array, for the exact same word, and if again you don't get any results, you need to search for the name.
Since you didn't specify a particular programming language, I assume you're using Flutter, as in the other questions of yours. So I will try to explain real quickly how to do it.
First, you need to create the following query:
final queryHobbiesByWord = users.where("hobbies", arrayContains: "word");
Then you have to call get(). As soon as you get a successful callback, you have to check if the number of documents that exist inside the QuerySnapshot is greater than zero. If it is, then perform the logic you want, otherwise, inside the callback create another query that looks like this:
final querySkillsByWord = users.where("skills", arrayContains: "word");
Do the exact same thing as about. If the number of documents that exist inside the QuerySnapshot is greater than zero, then perform the logic you want, otherwise, inside the callback create another query that looks like this:
final queryNameByWord = users.where("name", isEqualTo: "word");
Again, perform the same operation as above, and that's pretty much it. Don't forget to perform each operation inside the callback of the previous one.

Related

I need to get a specific document, where a document contains exactly two specific values

.collection('chats')
.where('members',
arrayContains: List.of([user1,user2]))
.snapshots();
I need to get a specific document, where 'members' contains exactly 'user1' and 'user2' only, and not just one of the values.
Also very important that the order of the values inside the 'members' array/list should be irrelevant..
Because this method using arrayContains is giving me any document that contains either one of these users.
What you're trying to do isn't possible exactly as you've specified. But you can do this if you assume the order of the elements in the array. For that, use a normal isEqualTo filter, providing the exact contents of the array to match. I don't write dart, but it should go something like this:
.where('members', isEqualTo: List.of([user1,user2]))
You can make sure the array always has a consistent order by sorting the items in the array before writing the field, and sorting the array you use in the query.
If the original order of the array is important, then maintain a duplicate field with the same array elements that are always sorted, and query that field instead of the original field.
See also:
FireStore query how to query arrays from the database

Querying MongoDB: retreive shops by name and by location with one single query

QUERYING MONGODB: RETREIVE SHOPS BY NAME AND BY LOCATION WITH ONE SINGLE QUERY
Hi folks!
I'm building a "search shops" application using MEAN Stack.
I store shops documents in MongoDB "location" collection like this:
{
_id: .....
name: ...//shop name
location : //...GEOJson
}
UI provides to the users one single input for shops searching. Basically, I would perform one single query to retrieve in the same results array:
All shops near the user (eventually limit to x)
All shops named "like" the input value
On logical side, I think this is a "$or like" query
Based on this answer
Using full text search with geospatial index on Mongodb
probably assign two special indexes (2dsphere and full text) to the collection is not the right manner to achieve this, anyway I think this is a different case just because I really don't want to apply sequential filter to results, "simply" want to retreive data with 2 distinct criteria.
If I should set indexes on my collection, of course the approach is to perform two distinct queries with two distinct mehtods ($near for locations and $text for name), and then merge the results with some server side logic to remove duplicate documents and sort them in some useful way for user experience, but I'm still wondering if exists a method to achieve this result with one single query.
So, the question is: is it possible or this kind of approach is out of MongoDB purpose?
Hope this is clear and hope that someone can teach something today!
Thanks

Mongoengine query based on reference field attribute

I have the following Documents
Food(Document)
title = fields.StringField()
type = fields.StringField()
Recipe(Document)
title = fields.StringField()
food = fields.ReferenceField(Food)
I would like to get the list of recipes whose food.type == "nonveg"
Can I do something like the following?
Recipe.objects.where(food__type="nonveg")
Thanks!
This is impossible with a single query, as Reference Field hold only the id of the actual document.
Hence, you need to do, two queries,
Which gets all the objects of Food, that fall under your type. This can be done via the code foods = Food.objects(type='nonveg')
Now, use the foods Objects List to filter the Recipe collection as : Recipe.objects(food__in=foods). Also, keep in mind that the in operation takes a list, so always pass a list into the filter query, even if you are getting a single instance in Step 1 using .get()
Wrapping up the steps:
foods = Food.objects(type="nonveg")
recipes = Recipe.objects(food__in=foods)
"type" is a reserved word in mongodb for an operator. So you should use this query : Recipe.objects(food__type__="nonveg")
Recipe.objects(food__type="nonveg") if you use mongoengine.

Is there an equivalent to `beginsWith` in Firestore?

The Firestore documentation on making queries includes examples where you can filter a collection of documents based on whether some field in the document either matches, is less than, or is greater than some value you pass in. For example:
db.collection("cities").whereField("population", isLessThan: 100000)
This will return every "city" whose "population" is less than 100000. This type of query can be made on fields of type String as well.
db.collection("cities").whereField("name", isGreaterThanOrEqualTo: "San Francisco")
I don't see a method to perform a substring search. For example, this is not available:
db.collection("cities").whereField("name", beginsWith: "San")
I suppose I could add something like this myself using greaterThan and lessThan but I wanted to check first:
Why doesn't this functionality exist?
My fear is that it doesn't exist because the performance would be terrible.
[Googler here] You are correct, there are no string operations like beginsWith or contains in Cloud Firestore, you will have to approximate your query using greater than and less than comparisons.
You say "it doesn't exist because the performance would be terrible" and while I won't use those exact words you are right, the reason is performance.
All Cloud Firestore queries must hit an index. This is how we can guarantee that the performance of any query scales with the size of the result set even as the data set grows. We don't currently index string data in a way that would make it easy to service the queries you want.
Full text search operations are one of the top Cloud Firestore feature requests so we're certainly looking into it.
Right now if you want to do full text search or similar operations we recommend integrating with an external service, and we provide some guidance on how to do so:
https://firebase.google.com/docs/firestore/solutions/search
It is possible now:
db.collection('cities')
.where('name', '>=', 'San')
.where('name', '<', 'Sam');
for more details see Firestore query documents startsWith a string

Mongo DB search based on multiple conditions

I am trying to search based on multiple conditions which works but the problem is that does not behave like this.
Assuming i have a search query like
Orders.find({$or: {"status":{"$in":["open", "closed"]},"paymentStatus":{"$in":["unpaid"]}}}
)
and i add another filter parameter like approvalStatus it does not leave the previously found items but rather it treats the query like an AND that will return an empty collection of items if one of the queries does not match.
How can i write a query that regardless of what is passed into it, it will retain previously found items even if there is no record in one of the conditions.
like a simple OR query in sql
I hope i explained this well enough
Using $or here is the right approach, but its value needs to be an array of query expressions, not an object.
So your query should look something like this instead:
Orders.find({$or: [
{"status": {"$in": ["open", "closed"]}},
{"paymentStatus": {"$in": ["unpaid"]}},
{"approvalStatus": {"$in": ["approved"]}}
]})