Firestore and flutter: update documents when a field is null - firebase

I have a collection which represents a list of available sport matches (see image below, sorry for the italian text).
Each document is a match, and has a list of players which are subscribed to that match (id_player1, id_player2, etc).
When someone would like to subscribe to that match, I have to cycle through the players_id, and when I find a null one, I set it to the user's id.
So my questions are:
how can I cycle through the fields of the document and check if they are null or not?
how can I count how many fields are not null, so when this count is equal to X, I do something?

You decide to define 6 different fields to store players id.. so u cannot cycle that fields.. what you can do is to get all of the six fileds and check one by one if they are null...
what you should do is to refactor that logic and store players id in a collection.. an update the collection only if its count is under 6 so you haven't t check if you have any space left to add player id
Bye :D

If there is no specific meaning to each individual id_player* field, consider storing all player IDs in a single player_ids array field.
That way you can use arrayUnion to add values to the field (preventing duplicates) and query with array_contains to find documents with a specific player ID.

Related

Query Firestore by value length

A question for the Firebase Firestore gurus out there.
I'm wanting to query a users collection for all documents where the bio field has a character length of <n
Is this possible?
I'm thinking this might have to be done post-query with some JS.
Firestore can only order/filter on values that are stored in the documents it returns. It cannot calculate any values, nor look values up.
So if you want to filter on the length of the bio, you'll have to store that value in a field in the document (e.g. bioLength) and update that each time you also update the bio.
With that field in place, you can then filter on it in a query.

Can I reuse existing fields as Sharded timestamps in Firestore?

I was looking for a solution to Firestore's limitation of Sequential indexed fields which means the following from this doc.
"Sequential indexed fields" means any collection of documents that
contains a monotonically increasing or decreasing indexed field. In
many cases, this means a timestamp field, but any monotonically
increasing or decreasing field value can trigger the write limit of
500 writes per second.
As per the solution, I can add a shard field in my collection which will contain random value and create a composite index with the timestamp. I am trying to achieve this with the existing fields I have in my Document.
My document has the following fields:
{
users: string[],
createdDate: Firebase Timestamp
....
}
I already have a composite index created: users Arrays createdDate Descending. Also, I have created Exemptions for the fields field from Automatic index settings. The users field will contain a list of firebase auto-generated IDs so definitely its random. Now I am not sure whether the field users will do the job of field shard form the example doc. In this way we can avoid adding a new field and still increase the write rate. Can someone please help me with this?
While I don't have specific experience that says what you're trying to do definitely will or will not work the way you expect, I would assume that it works, based on the fact that the documentation says (emphasis mine):
Add a shard field alongside the timestamp field. Use 1..n distinct values for the shard field. This raises the write limit for the collection to 500*n, but you must aggregate n queries.
If each users array contains different and essentially random user IDs, then the array field values would be considered "distinct" (as two arrays are only equal if their elements are all equal to each other), and therefore suitable for sharding.

How to get a parent collection by filtering data in a subcollection within the parent collection in firestore?

I'm developing a project with firebase, and I'm having trouble searching for a specific parent collection by filtering on one of its subcollections.
For example, when starting a trip, I must check which students (parent collection) have their presence confirmed (the going attribute must be true) and also the date of attendance should be equal to the date of the trip. How can I search for confirmed students (which would be the parent collection) when filtering data in the presence subcollection?
You would need to make these calls separately as there's no JOIN-like call in Firebase. In other words, you can't reference a document to call another.
To achieve it, you would need to consider something like querying all students who have going true and collate it will the results of the date of attendance match query.

Select documents where array field contains one of value from given array (array matching)

Consider the following data in Firestore:
I also have a set of selected by the user he's interested in: ['python', 'sql', 'swift']
How to get all the documents from my collection where tags field contains at least one of tags selected by the user? I'm aware that Firestore doesn't have such operator out of the box. Probably I need to rethink the way I store data somehow? Please point me to the right direction.
With the way you have your data structured, you will need to make one array-contains type query for each of the tags the user is interested in, then merge the results of each of those queries in your app code.

Voting on items - how to design database/aws-lambda to minimize AWS costs

I'm working on a website that mostly displays items created by registered users. So I'd say 95% of API calls are to read a single item and 5% are to store a single item. System is designed with AWS API Gateway that calls AWS Lambda function which manipulates data in DynamoDB.
My next step is to implement voting system (upvote/downvote) with basic fetaures:
Each registered user can vote only once per item, and later is only allowed to change that vote.
number of votes needs to be displayed to all users next to every item.
items have only single-item views, and are (almost) never displayed in a list view.
only list view I need is "top 100 items by votes" but it is ok to calculate this once per day and serve cached version
My goal is to design a database/lambda to minimize costs of AWS. It's easy to make the logic work but I'm not sure if my solution is the optimal one:
My items table currently has hashkey slug and sortkey version
I created items-votes table with hashkey slug and sortkey user and also voted field (containing -1 or 1)
I added field votes to items table
API call to upvote/downvote inserts to item-votes table but before checks constraints that user has not already voted that way. Then in second query updates items table with updated votes count. (so 1 API call and 2 db queries)
old API call to show an item stays the same but grabs new votes count too (1 API call and 1 db query)
I was wondering if this can be done even better with avoiding new items-votes table and storing user votes inside items table? It looks like it is possible to save one query that way, and half the lambda execution time but I'm worried it might make that table too big/complex. Each user field is a 10 chars user ID so if item gets thousands of votes I'm not sure how Lambda/DynamoDB will behave compared to original solution.
I don't expect thousands of votes any time soon, but it is not impossible to happen to a few items and I'd like to avoid situation where I need to migrate to different solution in the near future.
I would suggest to have a SET DynamoDB (i.e. SS) attribute to maintain the list of users who voted against the item. Something like below:-
upvotes : ['user1', 'user2']
downvotes : ['user1', 'user2']
When you update the votes using UpdateExpression, you can use ADD operator which adds users to SET only if it doesn't exists.
ADD - Adds the specified value to the item, if the attribute does not
already exist. If the attribute does exist, then the behavior of ADD
depends on the data type of the attribute:
If the existing data type is a set and if Value is also a set, then
Value is added to the existing set. For example, if the attribute
value is the set [1,2], and the ADD action specified [3], then the
final attribute value is [1,2,3]. An error occurs if an ADD action is
specified for a set attribute and the attribute type specified does
not match the existing set type. Both sets must have the same
primitive data type. For example, if the existing data type is a set
of strings, the Value must also be a set of strings.
This way you don't need to check whether the user already upvote or downvote for the item or not.
Only thing you may need to ensure is that the same user shouldn't be present on upvote and downvote set. Probably, you can use REMOVE or ConditionExpression to achieve this.

Resources