I have firebase database structure like this
All I want is those data which start with string '48DqysTKV0cMGf8orGlfhNaFLEw2' in the location "request/waiting"
My code is like below
But this code returns all the array in the waiting node not the specific nodes
The reason why is because you're using .childAdded. When called, initially it retrieves every element in the given path, thereafter it starts monitoring for added nodes only. More info.
Use .value instead in your query.
queryStarting(atValue) doesn't work the way you think it does. To achieve what you want, you need to limit your queries to a certain range/boundary. Read the different query types and decide for yourself which combination makes sense.
Try this (I think the problem in childAdded. Change it to .value):
let ref = FIRDatabase.database()
.reference(withPath: "request/waiting")
.queryStarting(atValue: "48DqysTKV0cMGf8orGlfhNaFLEw2")
.queryEnding(atValue: "48DqysTKV0cMGf8orGlfhNaFLEw2" + "\u{f8ff}")
ref.observeSingleEvent(of: .value, with: { snapshot in
if let data = snapshot.value as? [String: Any] {
// code..
}
})
The f8ff character used in the query above is a very high code point in the Unicode range. Because it is after most regular characters in Unicode, the query matches all values that start with a 48DqysTKV0cMGf8orGlfhNaFLEw2.
Hope it helps
Related
Please see the attached image, as I only know the value of the 2nd node(-M5Cc-PcLR9HfRQyJ0SU), is it possible to make query base on this and get the value of the 1st node (-M5ukIV79GHeUc0FnVUI)?
Thank you.
Firebase structure
It's not possible. You need to be able to build the full path of node to query. There are no wildcards.
You migth want to consider duplicating the data in such a way that you can find it without the parent node. This sort of data duplication is common in nosql type databases.
If we take the question literally, you don't need a query and the answer is yes, you can get to that data based on the information provided.
Again though, it will NOT be a query.
You asked:
get the value of the 1st node
To get the first node within the -M5Cc9t node, you would read the top level node -M5Cc-Pc... and then read the first node within that snapshot.
That will give you the -M5Cc9t node which contains Item 01. Again, you're asking for the 1st node and that will do it.
Here's the code based on your stucture (I abbreviated the node names)
func readChildNode() {
let nodeRefWeKnow = self.ref.child("DEVPCD").child("-M5uklV").child("-M5Cc-Pc")
nodeRefWeKnow.observeSingleEvent(of: .value, with: { snapshot in
let allSnapshots = snapshot.children.allObjects as! [DataSnapshot]
if let firstSnapshot = allSnapshots.first {
let name = firstSnapshot.childSnapshot(forPath: "name")
print(name)
}
})
}
and the output
Snap (name) Item 01
I am creating an iOS app where I have a standard set of user data in my firebase real time database. The user data consists of values such as name, age etc. Here is the structure:
user
- userId1
- name : Bob
- age : 25
- userId2
- name : Rob
- age : 24
- userId3
- name : Dylan
- age : 13
I also have another data named "connections" that has a structure as follows:
connections
- userId1
- userId2 : 1
- userId3 : 1
Let us say the current user ID is userId1. Now, when I press a button, I want to fetch all connections data for the userId1, which is userId2 and userId3. The question here is, how do I look into the "user" structure and get the relevant user information for userId2 and userId3?
In simple words, how do I filter data in a structure based on the data in another structure? Just can't seem to find the right solution online.
I am only able to fetch all the data. Have no clue how to filter the data.
First, you aren't filtering data, you are joining data. So having the correct mindset is an important starting point.
Assuming you're not fetching thousands of these at each request (which you shouldn't be in any case), the answer is that it probably doesn't matter. RTDB uses websockets and holds a pipeline open to the server, so requesting them individually or as a single query doesn't make much difference. It's really mostly about the byte count which doesn't change if you fetch each record or all the records in one go. So just fetch each user as needed.
At scale, don't be afraid to duplicate a little data for read efficiency. It's fine if you just need the names of the users to copy them directly into your data in places where you'll be performing large scale reads (in the hundreds of thousands or more).
There's a great series for Firestore that is mostly applicable to RTDB as well, which is a great primer to NoSQL data structures, particularly episodes #3 and #4.
Firebase can be a bit tricky when you first get started so here's some code to go along with the correct answer from Kato.
Conceptually, to begin with you want to know the uid's of this users connections. To do that, since we know this users uid, we can read the connection data directly from the connections node like this.
func readConnections() {
let uid = "userId1"
let thisUsersConnections = self.ref.child("connections").child(uid)
thisUsersConnections.observeSingleEvent(of: .value, with: { snapshot in
let connections = snapshot.children.allObjects as! [DataSnapshot]
for connection in connections {
let connectionUid = connection.key
self.printConnectionInfo(forUserId: connectionUid)
}
})
}
the snapshot that's populated will contain all of the child data of the userId1 node, which is
- userId2 : 1
- userId3 : 1
In this case, I want to read them in the order in which they appear in Firebase so we take that data contained in the snapshot and populate an array.
let connections = snapshot.children.allObjects as! [DataSnapshot]
Note the elements in the connections array are they in themselves DataSnapshots.
That array is iterated over to get each object (a DataSnapshot), and the .key of each snapshot is the uid of each of that users connections. The key is then passed to another function (for clarity) which reads in the user info for the passed in uid and prints the name and age to console.
func printConnectionInfo(forUserId: String) {
let usersRef = self.ref.child("users").child(forUserId)
usersRef.observeSingleEvent(of: .value, with: { snapshot in
let name = snapshot.childSnapshot(forPath: "name").value as! String
let age = snapshot.childSnapshot(forPath: "age").value as! Int
print(name, age)
})
}
I have the following array :
let messages = (fetchedResultsController.fetchedObjects as! [Message])
essentially, each element in this array is of the entity Message, where each Message has 5 core data attributes. Notably, the attribute I care about in this case is timestamp which is of type NSDate !!!!!!. I want to grab the message with the maximum date inside of this array using the reduce function. Please do not suggest to sort the messages first. I'am trying to avoid that. Thank you !
Not sure why you would want to use reduce, but I think this will work and fits with what you are looking for (assuming Swift 3):
let result = messages.max(by: {$0.timeStamp < $1.timeStamp})
so I've got a firebase database like this:
userIndexes
-- 1: uid1
-- 2: uid2
-- 3: uid3
I want to get the uid by using the key. So I'll query it like this:
DataService.sharedInstance.DB_REF_USERS_INDEXED_BY_ID.queryOrderedByKey().queryStarting(atValue: "2").queryLimited(toFirst: 1).observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.value)
})
When I use 2 or 3 as starting point, I get this print (here it's 2):
Optional({
2 = uid2; })
I easily can cast this to Dictionary<String, AnyObject>
But when I use 1 as starting point, I get this:
optional(<__NSArrayM 0x6000000494b0>( < null >,
uid1 ) )
If I try to cast this to a Dictionary, it just gets nil
Why is that?
I asked same question in forum ..
You should avoid arrays (specifically, numeric, sequential ids) in distributed systems.
For more on how array-like behaviors are handled in Firebase and Why you should avoid arrays:
It clearly defines in old firebase doc., whats going on when you use Arrays in firebase. check Arrays in firebase Database
You can also go through Best Practices: Arrays in Firebase .. where it says
if all of the keys are integers, and more than half of the keys between 0 and the maximum key in the object have non-empty values, then Firebase will render it as an array.
I want to query my data such that I get the objects whose timeStamps are in the range of my desired timeStamps.
My JSON data is:
"-KHbFGKIyefgWKEmlkY1" : {
"createdAt" : 1463094941,
"customer" : "user1",
"professional" : "professional1",
"service" : "service2",
"startsAt" : 1470070000,
"status" : "WaitingForApproval"
}
My code to make the query:
let minimumDesiredTimeStamp = 1470000000
let maximumDesiredTimeStamp = 1480000000
ref.queryOrderedByChild("startsAt")
.queryStartingAtValue(minimumDesiredTimeStamp)
.queryEndingAtValue(maximumDesiredTimeStamp)
.observeSingleEventOfType(.Value, withBlock: { (snapshotOfChildrenWhichStartsAtTimeStampRange) in
})
The problem is that query never jumps in the closure.
If it's not possible with current Firebase , can you suggest a way on how to achieve this?
NOTE: For now, I've solved the problem by querying with only combining queryOrderedByChild and queryStartingAtValue and then filtering the objects whose start time exceeds my range, with the help of Swift arrays' filter method.
NOTE2: When I tried the code again with hard coded values, I realised that the query really works. So it seems I've misidentified the problem and something else causing the query not jumping in the closure.
So remember: querying child values in combination of queryOrderedByChild.queryStartingAtValue.queryEndingAtValue works!