How to move a firestore document from one collection to another - android

Is this possible to move a document from one collection to another in Firestore Database? The reason I want to do this is, when someone deletes an Order, I want to move it to deleted_orders collection rather than deleting the entire document to keep the history.
I want to do this from my app which I have developed in Kotlin.

The only way to move a document from one collection to another collection is to use the following sequence, mimicking a "cut & paste":
Create a copy of the source document in the target collection, i.e. read it from the source collection, get the document fields and create a new document in the target collection with these fields, and then;
Delete the document from the source collection.
In other words, there is no kind of "metadata" attached to a document that defines its parent collection and that you could change in one simple action.
Another approach would be to have all the order docs in a unique collection and a field which holds the order status, e.g. active or deleted. Then changing the order status is just a matter of updating a field.
Note that this approach will not have any negative effect on your queries performance since Firestore query performance is proportional to the size of the result set, not the data set size.

private void insertAllFromOneCollectionIntoAnother(CollectionReference crFrom, CollectionReference crTo) {
QuerySnapshot querySnapshot = crFrom.GetSnapshotAsync().Result;
foreach (DocumentSnapshot documentSnapshot in querySnapshot.Documents) {
crTo.Document(documentSnapshot.Id.ToString())
.SetAsync(documentSnapshot.ToDictionary());
}
}

Related

Firebase Database: get all child's data from childs

I want to be able to differentiate my content between type and get all other data but I don't know how to get past the IDs after content.
I want every data from -NBC22CHEk3ebNxdlYOi, -NBC-Nfz6e5yppFlxU7S, -NBC1TVY-TzT7yfrSA3o
and later be possible to get new video id's from existing and new users
/content/{user_uid}/{content_uid}
If I want only the content from one user then I can write this:
val uid = FirebaseAuth.getInstance().uid
// url is just a placeholder for the real database url
val ref = FirebaseDatabase.getInstance(url).getReference("/content/$uid")
I want all content with the type value "video" from all users.
That's actually not possible with your actual database structure. All queries in the Realtime Database work on a flat list of nodes, where the value on which you want to perform the filter/order on, must be at a fixed path under each direct child node.
Unfortunately, that's not your case, because you have a dynamic key under the content node, which is actually the UID, and which also means that you can't filter on type. If you want to allow that, then you have to create a flat list of videos, where the UID (SIH5...89j1) is a property inside each video object. This is already achieved since publisher_uid holds exactly that.
In short, remove the extra (UID) level from your database tree. Or, leave it as it is, and denormalize the data. Basically create a new structure like this:
/content/{content_uid}
See, there is no UID involved. If you're new to NoSQL databases, this might sound some kind of weird, but it's actually a quite common practice.

How to get a document from a Cloud Firestore collection based on index?

For developing an Android app in Kotlin, I am trying to find a way to retrieve a document from a Firestore collection based on a certain index and I am not sure how to go about it. For example, if my collection has 50 documents, what would be the best way to retrieve the 10th document so that I can populate text views on my app based on the field values of that document?
Thank you for taking the time to answer my question.
When you add documents to Firestore using the CollectionReference#add() method, you'll see a random document ID that is assigned automatically for each document. If you check the Firebase Console or you try to query a collection programmatically, you will not find any order for the containing documents. This means that there is no index involved. So it's not correct to say, hey Firestore, give me the 10th document, because when you query a collection of 50 documents, the 10th document might be the one you are interested in, but if you add/delete documents, the 10th document won't be the same.
You might think, ok, I can provide my own document IDs, starting from 0 - 49, and when I query the collection I can order them by their document IDs. But, this is not an option, since the document IDs are always strings, and when you order strings, the order is lexicographical.
The best solution I can think of, if you need to get a particular document from a collection, is to add a specific field in that document, so it can be identified very easily. For instance, you can add a particular name or ID for each document, and then you can perform a query that looks like this:
rootRef.collection("users").whereEqualTo("name", "Bhavey")
In this way, you can simply identify each one of the documents in your collection.
To accomplish this, will require some setup.
let's say you have a collection of documents and you want to manage them and find the 10th document, Firestore generates unique hash id's that are based on the timestamp making them have an inherent order based on the time they were generated.
All you need to do is manage a dedicated document in the parent of this collection that contains an array of all document id's in the subcollection.
reading this document and it's array would get you an ordered list of documents without incurring the additional reads of the documents as other methods, even listing the ID's requires 1 read each.
on the successful operation of it being added, you can use a Cloud Function onCreate trigger to push the document id to the master array and the same with onDelete. But if cloud Functions are not available or you want to brute force it from the client, you can do the following:
db.collection("users")
.document("uid")
.collection("posts")
.add(city)
.addOnSuccessListener { documentReference ->
db.collection("users")
.document("uid")
.update("index", FieldValue.arrayUnion(documentReference.id))
.addOnSuccessListener { Log.d(TAG, "Index Added!") }
.addOnFailureListener { e -> Log.w(TAG, "Index Error", e) }
}
.addOnFailureListener { e -> Log.w(TAG, "Error source document", e) }
Cloud Functions sources:
trigger_a_function_when_a_new_document_is_created
trigger_a_function_when_a_document_is_deleted
*note: to scale this past 1mb firestore document limits - you will need multiple index documents with a counter and to manage this with Cloud Functions. The end result should double your writes without crippling your reads

Display images from Firebase Storage order by date added in Android

I am trying to display images from Firebase's storage in my Android app inside a GridView.
I have done that, however, the images are displaying in an unknown order, and I have noticed that there is a 'Last modified' column inside Firebase's storage when I upload the images to it.
My question is: is there a way that I could sort the images inside the GridView in order to display them according to that date? (for example, the last one added, would have the latest 'Last modified' date and would be viewed first and such...)
This is my code:
val listRef : StorageReference = FirebaseStorage.getInstance().reference.child("images/posts/$userName")
val fileNameList: ArrayList<String> = ArrayList<String>()
listRef.listAll()
.addOnSuccessListener { it ->
it.items.forEach{
fileNameList.add(it.name)
}
gridView?.adapter = ImageRecyclerAdapter(activity, fileNameList,userName)
}
Note: the code is in Kotlin
I have looked everywhere and couldn't find anything that helps.
Any help is appreciated, thank you :)
According to the official documentation regarding StorageReference's listAll() method:
List all items (files) and prefixes (folders) under this StorageReference.
You might not be interested in listing folders within the reference you are pointing to.
That been said, the best option that you have is to store the URLs in a database. Such a database can be either Cloud Firestore or Firebase Realtime Database. This means that each object should have at least two fields, one for the actual URL and one for a timestamp. Please see in my answer from the following post how you can add a timestamp to Firestore:
ServerTimestamp is always null on Firebase Firestore
Is in Java, but you can simply convert it to Kotlin. Once you have all URLs in place, you can create a query and order the URLs according to the date. In Firebase Realtime Database the default order is ASCENDING, but below is how you can reverse the order:
How to arrange firebase database data in ascending or descending order?
While in Firestore, you can simply pass the desired direction to Query's orderBy(String field, Query.Direction direction) method.

Filter and get all sub-collections by using where clause in Firestore

In firestore I have some sub-collections inside each collection just like below:
Collection1 -> id -> Sub-collection -> scId -> Data
So here I want to get all data from sub-collections by the help of the where clause. I tried one query like the below which is failing.
db.collection("Collection1").whereEqualTo("eDate", selectedDate)
.get().addOnSuccessListener(queryDocumentSnapshots -> {
List<Exp> mData = queryDocumentSnapshots.toObjects(Exp.class);
Here eDate is coming under the Data which is inside each sub-collection.
So is there any way to do that or any suggestions on how to do that or about the mistakes which I did here?
Firestore queries are shallow and do not extend above or below the named collection being queried. The query you show here will only return documents immediately within "Collection1". It will not consider any documents in nested subcollections.
If you want documents in a subcollection, you will have to build a CollectionReference to that subcollection, and query it individually. You can't query all subcollection nested under a document at the same time. You can't query across differently-named subcollections at the same time.
If this behavior does not meet the needs of your app, you should consider restructuring your data to do so, or building your app to perform as many queries as needed to get all the documents from among all the collections where they live.

Android's Firestore to join 2 collections into a recycler view

I have a users collection with uId, name, photo
I have a visits collection with uId, userId, location
I have a recyclerview in which I want to show the location with the user name and photo
Can I use the reference field type? If so, how will Firestore know to link visits.userId == users.uId ?
Maybe I first need to query all the visits and then query the relevant user but 2 things:
It means querying a lot of times.
I didn't understand how to collect the joined collection into the adapter, which is based on one query?
Please advice
Thanks
current code
visitsList = db.collection("visitsList");
Query query = visitsList.whereEqualTo("userId",prefs.getString("id","")).orderBy("visitDate", Query.Direction.ASCENDING);
FirestoreRecyclerOptions<AVisit> options = new FirestoreRecyclerOptions.Builder<AVisit>().setQuery(query, AVisit.class).build();
adapter = new VisitsListAdapter(options, VisitsListActivity.this);
RecyclerView rv = findViewById(R.id.rvVisitsList);
rv.setHasFixedSize(true);
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(adapter);
The code is a simple query from the collection, not sure how to get the name and photo from the userId field in that collection.
Can I use the reference field type?
Yes, you can use a reference field.
If so, how will Firestore know to link visits.userId == users.uId ?
Firestore results always comes from a single collection (at the moment). It does not automatically join the document from the users collection when you're reading from the visits collection. You will have to do this yourself.
That indeed means you'll be executing multiple reads, but it's often not nearly as slow as you may think. See Google Firestore - how to get document by multiple ids in one round trip?
Update: To show data from the user profile in a list of visits, there are two main options:
load the additional user document in populateView or with a custom parseSnapshot implementation.
duplicate the relevant user data in the visits collection (which is quite normal in NoSQL databases). Also see Alex' answer here: indexed query with FirestoreRecyclerAdapter.

Categories

Resources