Firestore - Fetch Subcollection Swift - firebase

Converting from Firebase to Firestore
I have a database that looks like the following
Above is a Firebase node for entries in a photo album. The top level node is the ID of the Album (reference from another node) and scoped under each albumID there is a node (auto gen id) for each album entry (or picture). The expanded album has two album entries, the first of which is expanded.
In Firebase - I could fetch the set of album entries (for a given album) by doing the following
I could offset to the subnode and read from there.
let dbKey = "byAlbum_entries"
let ref = Database.database().reference(fromURL: firebaseDB_URL)
let albumEntryReference = ref.child( dbKey).child( forAlbum.objectid)
albumEntryReference.observeSingleEvent(of : .value, with : { (snapshot) in ...
In Firestore how do I retrieve that same set of album entries?
is the correct syntax similar to below? Can I get documents from a document and Firestore will know I am asking to look for a subcollection because I said getDocuments()?
let dbKey = "byAlbum_entries"
let ref = Firestore.firestore()
let albumEntryReference = ref.collection( dbKey).document( forAlbum.objectid)
albumEntryReference.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
// no album entries found
} else {
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
// loop through album entries
}
}
}
Part 2 --- Data Model Good Practices with FIRESTORE
It is better to restructure the data so that there is no subcollection and there is just a single collection where each entry includes both the albumID and the AlbumEntryID and I can just use a where clause to fetch only the album entries where albumID matches the one I am looking for? This would require an additional index whereas currently, in firebase, I can go directly to where I want to read and just read.
Even if restructuring does turn out to be better, I'd still appreciate help on the syntax to fetch all album entries for a given album as the database currently exists.

Related

Firebase and Kotlin: getting the id of a document issues

I have an interesting issue while playing with Firebase and Kotlin.
val docRef = db.collection("Year")
.document(DB_year.toString())
.collection("Month")
.document((DB_month+1).toString())
.collection("Day")
.document(today)
.collection("write")
.get()
.addOnSuccessListener { result ->
for(document in result) {
println("document_id : " + document.id)
}
}
If you get the document id with this code, you can get it normally.
enter image description here
enter code here
This code cannot get the document id.
val docRef = db.collection("Year")
.document(DB_year.toString())
.collection("Month")
.document((DB_month+1).toString())
.collection("Day")
.get()
Why is it like this?
my firestore collection
enter image description here
enter image description here
As shown in your Firebase console screenshot above, the documents in the Day collection are displayed with an italic font in the Firebase console: This is because these documents are only present (in the console) as "container" of one or more sub-collection but are not genuine documents.
If you create a document directly under the write collection with the full path Year/docYear1/Month/subDocMonth1/Day/subDcoDay1/write/writeDoc, no intermediate documents will be created (i.e. no document in the Month or Day collections).
The Firebase console shows this kind of "container" (or "placeholder") in italic in order to "materialize" the hierarchy and allow you to navigate to the write document but the Day document doesn't exist in the Firestore database. Hence the empty result for your second query
See this answer for more details.
Note that if you want to get the parent ids (docs and collections) for a doc in the write collection, you can use the parent properties of the DocumentReference and CollectionReference.
So you can do something like:
db.collection("Year")
.document(DB_year.toString())
.collection("Month")
.document((DB_month+1).toString())
.collection("Day")
.document(today)
.collection("write")
.get()
.addOnSuccessListener { result ->
for(document in result) {
println("Day_doc_id : " + document.reference.parent.parent?.id)
}
}

Firestore How to retrieve subcollection

I am working on App that uses Firestore please see the following pic how I organize the data
I am trying to get data using the following code
let db = admin.firestore();
async function getMenu() {
let query = await db.collection('menu').orderBy("order", "asc").get();
const snapshot = query.docs;
snapshot.forEach((doc) => {
console.log(doc.id, '->', doc.data());
});
}
getMenu();
Output:
Feedings -> { order: 1 }
Diapers -> { order: 2 }
Can't able to get subcollection
Diapers & Wipes -> Disposable Diapers
Any Help will be appreciated.
It's not possible to get data from a subcollection using a query for a top-level collection. When you query menu, it will only ever give you document immediately within that collection. In this respect, Firestore queries are said to be "shallow".
If you want documents from a subcollection, you will need to make another query that targets that specific subcollection. For example:
db.collection("menu").doc("Diapers").collection("Diapers & Wipes").get()

Delete from Firebase Realtime Database

I have this structure of my database :
Posts
-> Key
-> PostId
-> PostName
-> PostDescription
-> PostDescription2
-> Location
-> Author
-> Date
-> Key
->
->
....
Somehow the field PostDescription has been duplicated in PostDescription2, I have n such nodes and I want to delete all entries of PostDescription2 from all the nodes. How can I do this ?
I did some search on google, but most articles tells about how to delete a child node or fields inside them using some logic in query. Also, I am a bit new to firebase.
You will need to execute this function ones. (Seams so) A sample of deletion code may look like into ie: posts path:
var dB = firebase.database();
var dBRef =dB.ref('posts');
dbRef.once('value', snpsht=>{
snpsht.forEach(dp =>{
var key = dp.key;
dB.ref('posts/' + key + '/PostDescription2').set(null);
})
})
This will delete all PostDescription2 field with setting value null. Consider that posts path is not a big data to avoid blocking the code. If so, you may get data with limitToLast option like:
var dBRef = dB.ref('posts').orderByChild('PostDescription2').limitToLast(1000);
This command will order the list by PostDescription2 and null value for the specified child key come first. and we collect from last 1000 items with above code.

How to get user specific data in Firebase Swift 3

I want to retrieve data of current user in the application. How can I do that. ?
Here is my current user's firebase id :
And my table node is :
Here it is clear that my uid and nodes title are different. So how can I get particular user's data.
My code till now:
self.ref = Database.database().reference()
let userID = Auth.auth().currentUser?.uid
self.ref.child("member").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
if !snapshot.exists() {
// handle data not found
return
}
})
You are getting different IDs, because the first one Wnlxl... is the userID and the other -KVvR664... is an autoID.
You have set .childByAutoID following the member, if you want to retrieve the data of the current user then, you have to put userID following member.
Then you can easily retrieve the user's data by userID because each and every detail will be saved under userID.
Hope this code will work for you.
let ref : FIRDatabaseReference!
ref = FIRDatabase.database().reference()
ref.child("member").child(user!.uid).setValue(["name": self.fullName.text!, "email": self.email.text!, "mobile": self.mobile.text!, "doj": self.doj.text!])
Your Firebase screenshot is incorrect I think - your code will work fine, but how you create these members are wrong.
When creating the members you are saying .childByAutoID which you should be using Auth.auth().currentUser?.uid. If that makes sense. Let me know.
Edit: to create a user with userUID data in the node member do the following:
if let userUID = Auth().auth.currentUser?.uid{
ref.child("members/\(userUID)").setValue(*YOURMEMBERINFODICTIONARY*)
}

Firebase,iOS: Appending key-value pair into a child node

I have the following User Table structure in Firebase
As you can see in the user that I have opened, I have a Posts section, inside this post section holds the Id's all articles which have been posted by this user.
The issue I am facing is as follows:
When the user creates a new article it's saved within the Posts Table, after the save I return the newly generated ID which I then pass on to the user table, I trying to insert the newly created ID into the post section of the user, so I assumed the URL would be something like this:
Users/{UserId}/Posts
However all this does it create a new section called posts, it doesn't actually insert the record into the given area.
My code which isn't working is as follows:
let linkPost = [childautoID: true]
FIRDatabase.database().reference().child("Users/\(UserId)/Posts").child(UserId).setValue(linkPost)
FYI the two id's that are currently inside Posts I added manually.
I've also tried the following:
FIRDatabase.database().reference().child("Users/\(UserId)/Posts").setValue(linkPost)
However all this does it remove all existing Id's and then inserts the new id.
I prefer something like this. This automatically append the data without fetching first
FIRDatabase.database().reference().child("Users/\(UserId)/Posts").child(UserId).setValue(true)
To append a key-value pair in Firebase Database child node use this :-
Make a Firebase Database Reference to the Posts node of that currentUser FIRDatabase.database().reference().child("Users").child(FIRAuth.auth()!.currentUser!.uid).child("Posts")
Check if Posts node exists in your user's DB, If not then create one by :- parentRef.setValue([postId : "True"]) in else block.
But if Posts node does exist retrieve it as a NSMutableDictionary , set the new object to it, and then store the updated Dictionary to that node.
func storePostsToDB(postID :String!, userID : String! = FIRAuth.auth()!.currentUser!.uid){
let parentRef = FIRDatabase.database().reference().child("Users").child(userID).child("Posts")
parentRef.observeSingleEventOfType(.Value, withBlock: {(friendsList) in
if friendsList.exists(){
if let listDict = friendsList.value as? NSMutableDictionary{
listDict.setObject("True", forKey: postID)
parentRef.setValue(listDict)
}
}else{
parentRef.setValue([postID : "True"])
}
})
}
Calling the function:-
storePostsToDB("yourPostID")// If you want to store in the currentUser DB
storePostsToDB("yourPostID", userID : otherUserID)//If you want to store the post in some other users database with uid `otherUserID`

Resources