Super simple query in firebase gone wrong (swift) - swift

I am trying to do a simple ordered query request based on epoch timestamps:
guard let user = Auth.auth().currentUser?.uid else {return}
let queryRef = Database.database().reference().child("ordersBackup").child(user).queryOrdered(byChild: "pickupCompleteAfter").queryLimited(toFirst: 1)
queryRef.observeSingleEvent(of: .childAdded, with: { (snapshot) in
print(snapshot.value)
})
Structure:
{
"UserId" : {
"UniqueId1" : {
"pickupCompleteAfter" : 1568314979000,
"name" : "Jeff"
},
"UniqueId2" : {
"pickupCompleteAfter" : 1557687779000,
"name" : "Stig"
},
"UniqueId3" : {
"pickupCompleteAfter" : "1578855779000",
"name" : "Ali"
}
}
}
It should return UniqueId2. However, I am always retrieving the same order as the structure i.e UniqueId1, UniqueId2, UniqueId3. It doesn't take the timestamp into consideration at all. What am I doing wrong?
Output:
LQ8nHi
{
orderInfo = {
deliveryCompleteAfter = 1552917600000;
deliveryCompleteBefore = 1552924800000;
pickupCompleteAfter = 156249280000;
pickupCompleteBefore = 1552492800000;
};
}
YQxeKv
{
orderInfo = {
deliveryCompleteAfter = 1552917600000;
deliveryCompleteBefore = 1552924800000;
pickupCompleteAfter = 1557687779000;
pickupCompleteBefore = 1552492800000;
};
}
ibIPO9
{
orderInfo = {
deliveryCompleteAfter = 1553090400000;
deliveryCompleteBefore = 1553097600000;
pickupCompleteAfter = 1578855779000;
pickupCompleteBefore = 1552665600000;
};
}

The pickupCompleteAfter is nested under the orderInfo node of each child. You're current not telling the database about that full path, so it only checks for a pickupCompleteAfter right under each child.
To order/filter on orderInfo/pickupCompleteAfter, use:
let query = Database.database().reference().child("ordersBackup").child(user)
.queryOrdered(byChild: "orderInfo/pickupCompleteAfter").queryLimited(toFirst: 1)
query.observeSingleEvent(of: .childAdded, with: { (snapshot) in
print(snapshot.value)

Related

How to add variables from a firebase snapshot

I know this question has been ask several times but none of the solutions work for me. here is my snap shot
Snap (CaseExtend) {
NYxdSlq8yOgQd3phssRlD = {
CaseMinute = {
WMKuImjuH0qPIGJhHHJKv = {
caseMinute = "";
dateTime = "Dec 1, 2021 12:20 PM";
minuteId = WMKuImjuH0qPIGJhHHJKv;
userId = OtRFaqilTigWvEkUCASvCoEegny1;
};
};
CaseParticipant = {
3f7nqmcWFTenePkEB9KoMHLzVtk2 = {
userId = 3f7nqmcWFTenePkEB9KoMHLzVtk2;
};
OtRFaqilTigWvEkUCASvCoEegny1 = {
userId = OtRFaqilTigWvEkUCASvCoEegny1;
};
};
caseId = Oj7TwzDC3HQMJKyTb8Ebi;
caseNumber = TEST;
court = "Labour Tribunal";
courtRoomNo = "";
date = "2021-12-01";
extendId = NYxdSlq8yOgQd3phssRlD;
extendStatus = "Not Extend";
location = "";
participantCount = 2;
profilePicture = "https://firebasestorage.googleapis.com/v0/b/lege-155e1.appspot.com/o/Profile%20Pictures%2FOtRFaqilTigWvEkUCASvCoEegny1.jpg?alt=media&token=676226fa-638b-4175-a8d5-247095f6b86a";
step = TBM;
time = "";
userId = OtRFaqilTigWvEkUCASvCoEegny1;
};
}
and i retrieve the snapshot using following code,
ref.child("CaseExtend").queryOrdered(byChild: "userId").queryEqual(toValue: "OtRFaqilTigWvEkUCASvCoEegny1" ).observe(.value, with: { (DataSnapshot) in
})
i want to add the caseID, caseNumber, date.. and other values for different variables. is there anyway i can do this?
first of all you are getting all data in casetExtend node all the variables you want to assign is not under that node. for that you need to navigate one level of child node.
ref.child("CaseExtend").queryOrdered(byChild: "userId").queryEqual(toValue: "OtRFaqilTigWvEkUCASvCoEegny1" ).observe(.value, with: { (snapshot) in
for caseSnapshot in snapshot.children.allObjects as! [DataSnapshot] {
let dict = caseSnapshot.value as? [String: AnyObject] // assign the snapshot to a dictionary
let court = dict!["court"] as? String ?? "unknown"; // assign the variable
}
})

Coredata update/insert for one to many relationship

I have a one to many relationship in my coredata object graph, typically User<->>Device. Lets say from my API i get a response of something as bellow
[
{
user:"John"
id:1
devices:[
{
id:1
name:"iPhoneX"
},
{
id:2
name:"Samsung Galaxy Plus"
}
]
},
{
user:"Peter"
id:"2"
devices:[
{
id:3
name:"iPhone5s"
},
{
id:4
name:"Samsung Galaxy"
}
]
}
]
Now the objective is to do a simple update/insert to my coredata tables. My Partial code as bellow for updating and inserting Device table
func updateDevice (userID:String, apiDevicesArray:[APIResposeDevice]){
for device in apiDevicesArray {
let request:NSFetchRequest<Device> = Device.fetchRequest()
request.predicate = NSPredicate(format:"id = %#", device.id)
do{
let searchResults = try self.privateMOC.fetch(request)
if searchResults.count > 0 {
//Update
let update_device = searchResults.last
update_device.name = device.name
update_device.id = device.id
}else{
//Stuck with inserting a device to the proper user
request.predicate = NSPredicate(format: "owner.id = %#, userID)
do{
let devicesArrayForUserID = try self.privateMOC.fetch(request)
//How to insert a record to this array now ???
}catch{
}
}
}catch{
}
}
}
First, you need to fetch the User.
Then, you have to choices:
user.devices.add(device)
or if it's two ways relationship, then you can call device.user = user

Bulk never returns error when setting options as { j: false }

Edited: New information added into the question
When using bulk operation with option journaling false it doesn't return code: 11000 duplicate key error.
When using following options, it doesn't return errors:
{ j:false }
{ w:0, j:false }
When using following options, it returns duplicate key errors:
{ w:"majority", j:false }
{ w:0, j:true }
{ w:"majority", j:true }
I wonder that is this a correct behaviour?
Code for example:
var ObjectId = mongoose.Types.ObjectId,
User = require('./models/user')
let bulk = User.collection.initializeUnorderedBulkOp()
let doc1 = {
"branch" : "DUPLICATE",
"department" : ObjectId("582bf1d8322809041e667777"),
}
let doc2 = {
"branch" : "TEST_SUCCESS",
"department" : ObjectId("582bf1d8322809041e668888"),
}
let doc3 = {
"branch" : "DUPLICATE",
"department" : ObjectId("582bf1d8322809041e669999"),
}
bulk.insert(doc1)
bulk.insert(doc2)
bulk.insert(doc3)
let bulkOptions = {
w:0,
j:false // next run change argument j as true
}
bulk.execute(bulkOptions, (err, result) => {
let writeErrors = result.toJSON().writeErrors
for (let i = 0; i > writeErrors.length - 1; i++) {
let error = writeErrors[i]
debug(error.toString())
}
})
Additionally the schema of User model has an unique compound index as userSchema.index({ branch:1, department:1 }, { unique: true })
App Version
mongoDB v3.4.3 (storageEngine is wiredTiger)
mongoose v4.12.4 (the documentation refers to node-mongodb-native API 2.2)
node.js v8.8.1

Firebase getting data in order

I am using Firebase and I have had no problems getting data in alphabetical order until recently. I never used queries, I always just used snapshots of data and sorted through them one-by-one. Recently, the data has not been always coming in alphabetical order in the snapVal. How do I make it so I get a snapVal of data sorted alphabetically, like it is in the snapshot from the database?
Real Example: there are 4 messages, id1-id4 (in that order). They contiain the message "1"-"4". The snapshot comes looking correct. But the snapVal (snapshot.value) looks like this:
["id2": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
}, "id4": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
}, "id1": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
}, "id3": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
}]
What the snapshot looks like:
["id1": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
}, "id2": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
}, "id3": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
}, "id4": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
}]
To get the snapVal, I use this:
if let snapVal = snapshot.value as? [String: AnyObject] {
// Comes out of order..
}
To clarify:
Snapshot (this ends up coming out correct):
Snap (CHAT) {
id1 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
};
id2 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
};
id3 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
};
id4 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
};
}
This is the output for print(snapVal.keys) inside if let snapVal = snapshot.value as? [String: AnyObject]:
LazyMapCollection<Dictionary<String, AnyObject>, String>(_base: ["id2": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
}, "id4": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
}, "id1": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
}, "id3": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
}], _transform: (Function))
My Code:
self.firebase.child("Chats").child(chatID).queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
if let snapVal = snapshot.value as? [String: AnyObject] {
print(snapVal)
for c in snapVal {
print("checking Message as child")
let message = c.value["MESSAGE"] as? String
let fn = c.value["FIRST_NAME"] as? String
let ln = c.value["LAST_NAME"] as? String
let USER_ID = c.value["ID"] as? String
if let userID = USER_ID {
if let msg = message {
if let firstName = fn {
if let lastName = ln {
let username = "\(firstName) \(lastName)"
self.addMessage(userID, text: msg, name: username)
print("Message added! \nMessage Info:")
print("User ID: \(userID)")
print("text: \(msg)")
print("Username: \(username)")
} else {
print("LN did not pass")
}
} else {
print("FN did not pass")
}
} else {
print("Msg did not pass")
}
} else {
print("User ID did not pass")
}
}
}
})
Since you haven't shared the necessary code, I'll assume you're doing something along these lines:
ref!.queryOrdered(byChild: "text").observe(.value, with: { (snapshot) in
print("\(snapshot.value)")
})
When you execute a query on a Firebase location, the data is returned with information about the order of the items according to the query. When you observe a value event, the snapshot contains the keys, the values and the order of the children.
But when you convert request the snapshot.value property, all information has to be converted into a dictionary. The keys and the values of each child survive this conversion, but the information on ordering is lost.
For this reason, you'll have to use the children property of the snapshot to iterate over the children in the correct order:
ref!.queryOrdered(byChild: "text").observe(.value, with: { snapshot in
for child in snapshot.children {
print("child \(child)")
}
})
Solution: After very extensive searching and attempting, the problem still persisted that once the snapshot was converted to a snapVal (snapshot.value), the order often rearranged. My (working) solution:
for child in snapshot.children {
let child = child as! FIRDataSnapshot
if let childVal = child.value as? [String: AnyObject] {
let childMessage = childVal["MESSAGE"] as! String
// more code for each child. This child might be a post of a sort, which you can access properties of in a way like I did in the line above
}
}
Process:
Loop through each child in snapshot
Convert the child to a FIRDataSnapshot so it is not an element
Get the value of the particular child to access properties from
Add in the respective code for the child following NSDictionary principles.
Why this solution is solid
Receiving snapshots in the proper order is very simple. The issue I faced was getting data in the correct order when I got the snapshot.value. This solution fixes that because the values of each child are only accessed when looping through the children of snapshot, which is sorted. This leaves the order of children still in the control of the snapshot.
I also like the snapshot.value approach by using [String: AnyObject] because it is very close to the old functionality of Firebase implementation in Swift: Simple and very clean. I actually think that using NSDictionary in this way is really a way to save time in the long run because it is not verbose in any way.
From my experience with Firebase you cannot guarantee the order that the data is being returned in the snapshot value. Firebase provides a couple of functions that you can add to your reference query though to order and sort the data based on key queryOrderedByKey, value queryOrderedByValue, or child queryOrderedByChild.
From your description it sounds like you may want to use queryOrderedByChild to sort you snapshots correctly.
Here's the documentation on those functions and scroll down to the sort data section. https://firebase.google.com/docs/database/ios/lists-of-data
The problem as you can see is not that Firebase is not giving you the response ordered by as requested, the problem is that you are parsing the response into an Dictionary and Dictionaries are no ordered list. The simplest way to fix it is to order your dictionary using something like this:
self.messages.sortInPlace({ ($0.date.compare($1.date) == NSComparisonResult.OrderedAscending)})
Or a even better way is to add the result directly into an array.
You can find more about this problem in this question in my course, there is a long discussion about it there (https://www.udemy.com/firebase/learn/v4/questions/1341056).
Let me know if that helps you.

Load Specific data from JSON with Random Values Swift

I am using firebase and I am trying to retrieve data from Firebase Database which is working well however when I call "postDict" I get.
["-KPZAOg58kUdqwYMzlDJ":
{
description = jpeg;
listingImageURL = "https://firebasestorage.googleapis.com/v0/b/hype-central.appspot.com/o/lidsafstings%2FC73FdfB8A0-968df7-44DB-B96B-A10DC1E3A2B7.png?alt=media&token=b6e296f2-8854-4b76-9bfc-470dfd69d11f2f";
location = jpeg;
price = 54;
title = jpeg;
userDisplayName = "Brandon YOIO";
userid = pRuwvL7WyzQpY0G22ZLYCmTTemB3;
},
"-KPZ0yLhcfLvP9YWNjbC": {
description = "Description ofvaroe";
listingImageURL = "https://firebadfasestorage.googleapis.com/v0/b/hype-central.appspot.com/o/listings%2F0ACdasfCD645-2E2C-4936-B3DF-37EC55AA0157.png?alt=media&token=b321dasff42f-75b5-4eb3-b129-b0a902cc5926";
location = Vancouver;
price = 34;
title = eclipse;
userDisplayName = "Brandon YOIO";
userid = pRuwvL7WyzQpY0G22ZLYCmTTemB3;
},
"-KPoCsNS63JZdbTJIdaP": {
description = Brandon;
listingImageURL = "https://firebadasfsestorage.googleapis.com/v0/b/hype-central.appspot.com/o/listings%2FOptional(%22pRuwvL7WyzQpY0G22ZLYCmTTemB3%22)%2F3EACE28E-D28A-464A-B6D0-FB502E9dafsB4775.jpeg?alt=media&token=1d45bc7b-7273-4d33-8ccd-755f3102a23c";
location = BRANDON;
price = BRANDON;
title = BRANDON;
userDisplayName = "Brandon YOIO";
userid = pRuwvL7WyzQpY0G22ZLYCmTTemB3;
},
"-KP_Y7ug7hwrHtW6VNqV": {
description = "Description ofvaroe";
listingImageURL = "https://firebaseddasfstorage.googleapis.com/v0/b/hype-central.appspot.com/o/listings%2FC5daf7991BA-D7E0-4C8A-96E7-0DB17EEBABD7.jpeg?alt=media&token=efd03b4d-6964-4685-9b48-5ed36a4ceb59";
location = "";
price = "";
title = "";
userDisplayName = "Brandon Mayhew";
userid = pRuwvL7WyzQpY0G22ZLYCmTTemB3;
}]
If I call "postDict["-KPZAOg58kUdqwYMzlDJ"]["title"]" It will print the title which is exactly what I want however how do I get an array of all the titles in this JSON format (not just the title of "-KPZAOg58kUdqwYMzlDJ").
How do I get all the title's?
Use :-
rootRef.observeEventType(.Value, withBlock: {(postDictionary) in
if let postDict = postDictionary.value as? [String:AnyObject]{
for each in postDict as [String:AnyObject]{
let autoID = each.0
rootRef.child(autoID).observeEventType(.Value, withBlock: {(specificPost) in
//RETRIEVE YOUR DATA
})
}
}
})
PS:- I have used rootRef as you have not specified your parent nodes in your JSON structure :)