Reputation: 5
groups
--group1(autoid)
---subgroup1(autoid)
----id
----ownerId
----description
--group2(autoid)
---subgroup2(autoid)
----id
----ownerId
----description
In a structure like over here i have to count all occurrencies of ownerId that are equal to my id (currentUserId) in all groups, can somebody help me?
what i've done so far:
root.child("groups").observe(.value, with: {(snapshot) in
if let result = snapshot.children.allObjects as? [DataSnapshot] {
var count = 0
for child in result {
let orderID = child.key as String //get autoID
self.root.child("groups/\(orderID)/").queryOrdered(byChild: "ownerId").queryEqual(toValue: self.currentUserId).observe(.value, with: { (snapshot: DataSnapshot!) in
print(snapshot.childrenCount, "quanti sono")
count += (Int(snapshot.childrenCount))
print(count)
})
}
}
})
with this i can get a count but it updates all cycles... i need i need the final value outside
Upvotes: 0
Views: 808
Reputation: 35658
One important aspect of Firebase Structures is denormalizing or flattening the structure. Denormalized data generally makes queries much easier and while conceptually the structure you are using works for some tasks, it makes doing the query you want challenging.
So, I would suggest an alternate structure that would make the query super simple, and not loose other functionality.
A change to the structure like this:
groups
group1: true
group2: true
subgroups
subgroup1(autoid)
id
ownerId
description
belongs_to_group: "group1"
subgroup2(autoid)
id
ownerId
description
belongs_to_group: "group2"
Then if you want to count all of subgroups with a particular ownerId
let subGroupsRef = self.ref.child("subgroups")
let query = subGroupsRef.queryOrdered(byChild: "ownerId").queryEqual(toValue: "their id")
query.observeSingleEvent(of: .value) { snapshot in
let count = snapshot.childrenCount
print(count)
}
Edit:
Based on the comment, here's an way to get the count based on your current structure. It's pretty brute force and the code could be reduced considerably but I left it verbose for readability
let groupsRef = self.ref.child("groups")
groupsRef.observeSingleEvent(of: .value, with: { snapshot in
var count = 0
for groupChild in snapshot.children {
let groupSnap = groupChild as! DataSnapshot
for subGroupChild in groupSnap.children {
let subGroupSnap = subGroupChild as! DataSnapshot
let dict = subGroupSnap.value as! [String: Any]
let uid = dict["owner_id"] as! String
if uid == "uid_0" {
count += 1
print(count)
}
}
}
print("total found \(count)")
})
Where this fails is if you have a lot of nodes as they are all initially loaded in (by .value) so it could be iterated over in code. If it's a few thousand it works well and is very fast.
Upvotes: 1
Reputation: 4708
You can achieve this step by doing a single observe
of .childAdded
type. The .childAdded
on an sub child, in your example groups
, is like a for loop that iterate all nodes.
With this configuration you can append a .queryOrdered(byChild:)
and a .queryEqual(toValue:)
:
ref.child("groups")
.queryOrdered(byChild: "ownerID")
.queryEqual(toValue: 123)
.observe(.childAdded)
{ (snap) in
print(snap)
}
After that, if you want to count all this child, you need to add a property on your class
This is a test example:
To optimize performance remember to add a .indexOn
rule on your firebase app:
"groups" : {
".indexOn" : "ownerID"
}
Hope this help you ;)
Upvotes: 0