Firebase dataSnapshot sub-node - swift

I am trying to snapshot the shopping lists of a user. The snapshot works fine, except for the products node.
Link to db:
This is my observer:
func observeLists(callBack: #escaping (_ list: [List]) -> Void){
let dbRef = database.child("list").child(ShareData.shared.userId)
dbRef.queryOrdered(byChild: "completed").observe(.value, with: { snapshot in
var newItems: [List] = []
for child in snapshot.children {
if let snapshot = child as? DataSnapshot {
let groceryItem = List(snapshot: snapshot)
newItems.append(groceryItem)
}
}
callBack(newItems)
})
}
And this is my init(snapshot) from struct List
init(snapshot: DataSnapshot) {
let id = snapshot.key
let value = snapshot.value as? NSDictionary
let products = value?["products"] as? [Product] ?? []
let completed = value?["completed"] as? Bool ?? false
let storeId = value?["storeId"] as? String ?? ""
let name = value?["name"] as? String ?? ""
self.init(id, products, completed, storeId, name)
}

The products node in your database is not an array of products ([Product]), but rather a dictionary/map ([String: Product]).

Related

Swift filtering firebase data by child node

I'm trying to filter my firebase data within the table view to group items that have the same category (child value) after each other. Currently, it's not returning the values based on the child value. I think it's being done in random order.
Here is my code:
How I'm attempting to filter the data:
self.items.append(item)
self.items.sort(by: { (item1, item2) -> Bool in
return item1.category.compare(item2.category) == .orderedSame
})
self.tableView.reloadData()
Model:
struct Item {
var id: String?
var user: User
var fromId: String?
let item: String
let category: String
let creationDate: Date
init(user: User, dictionary: [String: Any]) {
self.user = user
self.item = dictionary["item"] as? String ?? ""
self.fromId = dictionary["fromId"] as? String ?? ""
self.category = dictionary["category"] as? String ?? ""
let secondsFrom1970 = dictionary["creationDate"] as? Double ?? 0
self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
}
}
Fetch function:
fileprivate func fetchListItems() {
self.tableView.refreshControl?.endRefreshing()
guard let uid = Auth.auth().currentUser?.uid else { return }
guard let listId = list?.id else { return }
let ref = Database.database().reference().child("lists").child(listId).child("list-items")
ref.observe(.childAdded) { (snapshot) in
let itemId = snapshot.key
let itemRef = Database.database().reference().child("items").child(itemId)
itemRef.observeSingleEvent(of: .value, with: { (snapshot) in
let itemId = snapshot.key
guard let dictionary = snapshot.value as? [String: Any] else { return }
guard let uid = dictionary["fromId"] as? String else { return }
Database.fetchUserWithUID(uid: uid, completion: { (user) in
var item = Item(user: user, dictionary: dictionary)
item.id = snapshot.key
self.items.append(item)
self.items.sort(by: { (item1, item2) -> Bool in
return item1.category.compare(item2.category) == .orderedSame
})
self.tableView.reloadData()
ref.keepSynced(true)
})
})
}
}
Database:

How to Update CollectionView Model with Firebase?

I am trying to intitialize my Collection View Model which holds a list of [Users] with a firebase snap that holds data.
Here is the Collection View Model code:
typealias JSON = [String:Any]
class HomeDataSource: Datasource {
var users: [User]
init?(with snapshot:DataSnapshot) {
var users = [User]()
guard let snapDict = snapshot.value as? [String: [String:Any]] else {return nil}
for snap in snapDict {
guard let user = User(dict: snap.value) else {continue}
users.append(user)
}
self.users = users
}
}
User Model:
struct User {
let name: String
let username: String
init?(dict: JSON) {
guard let name = dict["name"] as? String,
let email = dict["email"] as? String
else {return nil}
self.name = name
self.username = email
}
}
Firebase Snap:
Snap (users) {
8CVeHMNHI6hZAWj1zhGHEjPwYYz1 = {
email = "Silviu#isidors.sjsj";
name = Bshdjdj;
};
9CuqgR4Es7TOPPJQEpSnQXlfYnm1 = {
email = "Test#silviu.com";
name = "Test#silviu.com";
};
DBqGWlpdJKME570euqUz2rqI5Z83 = {
email = "Test#test.test";
name = Test;
};
}
Fetch Function:
func fetchUser() {
let ref = Database.database().reference().child("users")
ref.observe(.childAdded, with: { (snapshot) in
let user = User(dict: snapshot.value as! JSON)
self.users.append(user!)
print(self.users)
let new = HomeDataSource(with: snapshot)
print(new)
DispatchQueue.main.async(execute: {
self.datasource = new
self.collectionView?.reloadData()
})
}, withCancel: nil)
}
Right now, I am getting an array of Users from Firebase, however my collection view won't update.
My question is how should I update my Collection View Model and Fetching Function so it can fetch data from Firebase and Populate the Collection View Correctly?
So the problem was the node I was targeting. Removed "child("users")" form fetching function and targeted the whole users node with uids. Then I was looping the snapshot.value while I casted it in [String:[String:Any]], because each snapshot.valuelooked like this (key: "vijwUkzAlbgcqjAammfy0JuVMB33", value: ["name": Silviu, "email": Office#isidors.com]) Finally, I updated the HomeDataShource Class like this:
class HomeDataSource: Datasource {
var users: [User]
init(with snapshot:DataSnapshot) {
var users = [User]()
let snapDict = snapshot.value as? [String:[String:Any]]
for snap in snapDict! {
guard let user = User(snap: snap.value) else {continue}
users.append(user)
}
self.users = users
}

Posts Being Uploaded Randomly in Collection View - Swift & Firebase

I have been refactoring my code and now I'm having trouble with the posts.
Whenever I add a new post to the collection view, it is being added in a random cell and out of order, instead of in the first post.
I know the reason is the fetchuser function and from what I'm being told due to the asynchronous loading, but don't know what to do in order to correct this.
Could someone help me figure out what to do so that my posts are added in the first cell?
#objc func observePostsAdoption() {
let postsRef = Database.database().reference().child("posts")
postsRef.queryOrdered(byChild: "postType").queryEqual(toValue: "adopt").observe(.value) { (snapshot) in
var tempPost = [Posts]()
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot {
let dict = childSnapshot.value as? [String: Any]
let newAdoptiondPost = Posts.transformPost(dict: dict!)
//This will look up all users at once
self.fetchUser(userid: newAdoptiondPost.userid!, completed: {
tempPost.insert(newAdoptiondPost, at: 0)
DispatchQueue.main.async {
self.postsadoption = tempPost
self.adoptionCollectionView.reloadData()
self.refresherAdoption.endRefreshing()
}
})
}
}
}
}
func fetchUser(userid: String, completed: #escaping ()-> Void ) {
Database.database().reference().child("users").child(userid).observeSingleEvent(of: .value) { (snapshot) in
if let dict = snapshot.value as? [String: Any] {
let user = UserProfile.transformUser(dict: dict)
self.users.insert(user, at: 0)
completed()
}
}
}
Here's my Post Struct
class Posts {
//UserView
var uid: String?
var author: UserProfile?
var timestamp: Date?
var userid: String?
func getDateFormattedString() -> String {
let formatter = DateFormatter()
formatter.dateFormat = "MMM d, HH:mm"
return formatter.string(from: self.timestamp!)
}
//Image
var photoUrl: URL?
//PostInformation View
var city: String?
var municipality: String?
var name: String?
var breed : String?
var phone : String?
var address : String?
var petType: String?
var genderType: String?
var comments: String?
}
extension Posts {
static func transformPost(dict: [String: Any]) -> Posts {
let post = Posts()
//Post Picture
let photoUrl = dict["photoUrl"] as? String
post.photoUrl = URL(string: photoUrl!)
//INFO POSTS
post.userid = dict["userid"] as? String
post.city = dict["city"] as? String
post.municipality = dict["municipality"] as? String
post.name = dict["name"] as? String
post.breed = dict["breed"] as? String
post.phone = dict["phone"] as? String
post.address = dict["address"] as? String
post.comments = dict["comments"] as? String
post.petType = dict["petType"] as? String
post.genderType = dict["gender"] as? String
let timestamp = dict["timestamp"] as? Double
post.timestamp = Date(timeIntervalSince1970: timestamp!/1000)
return post
}
}
If you already have the posts ordered by post type you can just do sorting depending on the timestamp. For example
#objc func observePostsAdoption() {
let postsRef = Database.database().reference().child("posts")
postsRef.queryOrdered(byChild: "postType").queryEqual(toValue: "adopt").observe(.value) { (snapshot) in
var tempPost = [Posts]()
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot {
let dict = childSnapshot.value as? [String: Any]
let newAdoptiondPost = Posts.transformPost(dict: dict!)
//This will look up all users at once
self.fetchUser(userid: newAdoptiondPost.userid!, completed: {
tempPost.insert(newAdoptiondPost, at: 0)
DispatchQueue.main.async {
self.postsadoption = tempPost
self.postsadoption.sort { (p1, p2) -> Bool in
return p1.timeStamp?.compare(p2.timeStamp!) == .orderdDescending
}
self.adoptionCollectionView.reloadData()
self.refresherAdoption.endRefreshing()
}
})
}
}
}
}
With that the posts adoption array will be sorted depending on the timestamp that you have.

Using DispatchGroup within multiple for loop - Swift & Firebase

I'm having an issue with getting dispatchgroup functions to work when combined with multiple for loops. In my code below, my first dispatch pulls in the coauthorId field for each of the coauthorID under my userId.
I'm getting an error when the code reaches the first dispatchgroup.leave() function so I'm not sure if it has something to do with where the dispatchgroup functions are placed.
Datebase structure:
posts
--ABC //my userId
--XXX //coauthorId
--coauthorId: XXX
--ZZZ //coauthorId
--coauthorId: ZZZ
--YYY //coauthorId
--coauthorId: YYY
Code:
var ListA = [String]()
var ListB = [String]()
func fetchPosts() {
let dispatchGroup = DispatchGroup()
let currentUser = Auth.auth().currentUser!
dispatchGroup.enter()
Database.database().reference().child("posts").child(currentUser.uid).observeSingleEvent(of: .value, with: { (snapshot : DataSnapshot) in
// Iterate through all the children:
for child in snapshot.children.allObjects as! [DataSnapshot] {
let value = child.value as? NSDictionary
let coauthorId = value?["coauthorId"] as? String ?? ""
Database.database().reference().child("posts").child(coauthorId).observeSingleEvent(of: .value, with: { (snapshot : DataSnapshot) in
// Iterate through all the children:
for child1 in snapshot.children.allObjects as! [DataSnapshot] {
let value1 = child1.value as? NSDictionary
let coauthorId1 = value1?["coauthorId"] as? String ?? ""
self.ListA.append(coauthorId1)
dispatchGroup.leave() //this is where I get an error
}
})
}
})
dispatchGroup.enter()
//fetches the Id of my posts
Database.database().reference().child("posts").child(currentUser.uid).observeSingleEvent(of: .value, with: { (snapshot : DataSnapshot) in
// Iterate through all the children:
for child in snapshot.children.allObjects as! [DataSnapshot] {
// Add the user ID to the array:
let value = child.value as? NSDictionary
let mycoauthorId = value?["coauthorId"] as? String ?? ""
self.ListB.append(mycoauthorId)
}
dispatchGroup.leave()
})
// Notify the dispatch group:
dispatchGroup.notify(queue: DispatchQueue.main, execute: {
// Now that both completion blocks (from your two observers) ran, combine both arrays
let combinedArray = self.ListA + self.ListB
print(combinedArray)
})

Can't get node of firebase children

Hi there i'm newest in swift. I am working with a firebase database with at 2 layer of hierarchy as well as many children for each node. I got 1st layer (descript, enddata and other), but i stll can't get the news node. Is in 3 to 5 random keys. I sow many issues but still not have issue for me.
I'm understand i'm doing some wrong but what?
The Firebase is:
i need retreat the news child
struct is
struct ICONews {
let ICOId: String
let news1: String
let news2: String
let news3: String
init?(ICOId: String, dict: [String: Any] ) {
self.ICOId=ICOId
guard let news1 = dict[""] as? String,
let news2 = dict[""] as? String,
let news3 = dict[""] as? String
else { return nil }
self.news1 = news1
self.news2 = news2
self.news3 = news3
}
}
struct NewsSnapShot {
let posts: [ICONews]
init?(with snapshot: DataSnapshot) {
var posts = [ICONews] ()
guard let snapDict = snapshot.value as? [String: [String: Any]] else { return nil }
for snap in snapDict {
guard let post = ICONews (ICOId: snap.key, dict: snap.value) else {continue}
posts.append(post)
}
self.posts=posts
}
}
class of DataBase
class DatabaseService {
static let shared = DatabaseService()
private init(){}
let ICOReference = Database.database().reference()
}
and retreat method
DatabaseService.shared.ICOReference.child("news").observe(DataEventType.value, with: { (snapshot) in
guard let postsSnapShot = ICOSnapShot(with: snapshot) else {return}
})
done
Database.database().reference().observeSingleEvent(of: .value, with: {(snapshot) in
let enumerator = snapshot.children
while let rest = enumerator.nextObject() as? DataSnapshot {
let values = (rest as! DataSnapshot).value as? NSDictionary
let enumeratorMap1 = (rest as! DataSnapshot).children
while let rest2 = enumeratorMap1.nextObject() as? DataSnapshot {
let valuesMap1 = (rest2 as! DataSnapshot).value as? NSDictionary
if (rest2 as! DataSnapshot).key == "news" {
print(rest2.value)
}
}
}
})
Make the the Firebase Api call like
Database.database().reference().child("users").child(userID).observe(.childAdded, with: { (snapshot) in
if snapshot.exists() {
let receivedMessage = snapshot.value as! [String: Any]
let name = receivedMessage["name"] as? String ?? ""
let id = receivedMessage["id"] as? Double ?? 0.0
let profileurl = receivedMessage["url"] as? String ?? ""
completion(User(name: name, id: id, url: url))
} else {
failure()
}
})