How can I save this object model data to Firebase - ios

I have a model for a routine like the following:
struct Routine {
var routineName: String!
var routineExercisesAndSets: [String:Int]!
}
And a UITableView where I collect data before creating a new instance of that model, which once created looks like:
var routine = Routine()
//values are assigned to the routine here and then when printed looks like below
(routineName: All Over,
routineExercisesAndSets: ["Bent Over Row": 3, "Barbell Curl": 3, "Bench Press (Flat)": 4])
How could I save this into Firebase so that it fits my data structure
"routines": {
"users unique identifier": {
"routine unique identifier": {
"routine_name": "routine name",
"routine_create_date": "routine created date",
"exercises": {
"exercise name": {
"Sets": "number of sets",
"rest between sets": "timer duration"
}
}
}
}
}
The user unique identifier will be the current logged in users uid and routine unique identifier will be an autoId, but how can I work through the model to push data to Firebase the same as the model?

If your user is authenticated try this:-
FIRDatabase.database().reference().child("routines/\(FIRAuth.auth()!.currentUser!.uid)").childByAutoId().setValue([
"routine_Name" : "All Over",
"routine_create_date": "routine created date",
"exercises": [
"exercise name": [
"Sets": "number of sets",
"rest between sets": "timer duration"
]]
])

Related

Decoding Multiple JSON URLs into a Single Class

I'm attempting to decode multiple JSON URLs into a class. Since I'm using an API, I have no control over the fact that the JSON data is split into two URLs. Here is the problem statement:
I have a class called Student
JSON URL student_info.json contains a dictionary with all students and the Student instance constants A, and B.
JSON URL student_status.json contains Student instance variables C, D, and E.
I need to do the following:
Retrieve the dictionary of students from student_info.json to populate a collection of Students and instantiate them with attributes A and B.
Save this Student collection so that it is accessible throughout the rest of the app's lifecycle.
Retrieve the dictionary of student information from student_status.json and populate Student instance variables C, D, and E for each student in the collection.
From time to time, update the collection of students (in case any were dropped or added).
From time to time, update variables C, D, and E for each student in the collection.
Here are some example files:
File:
student_info.json
Content:
{
"last_updated": 1535936693,
"tyl": 10,
"data": {
"students": [
{
"student_id": "1",
"name": "John Appleseed",
},
{
"student_id": "2",
"name": "Jane Doe"
}
]
}
}
File:
student_status.json
Content:
{
"last_updated": 1535936693,
"tyl": 10,
"data": {
"students": [
{
"student_id": "1",
"number_of_classes": "10",
"GPA": "2.87",
"tuition_due": "237.33"
},
{
"student_id": "2",
"number_of_classes": "10",
"GPA": "2.87",
"tuition_due": "237.33"
}
]
}
}
File
Student.swift
Content
class Student {
var student_id: Int
var name: String
var numberOfClasses: Int?
var gpa: Double?
var tuitionDue: Double?
}

How to provide custom IDs during JSON import in Firebase Database?

How can I set the ID of the record or doc in the Firebase Database when I use the JSON import functionality?
When I import the file it creates sequential IDs (0, 1, 2 etc), but I would like to specify an ID so its easier to retrieve the record.
Below is my sample JSON data:
[
{
"GameID": 2234567890,
"GameName": "Team 3 vs Team 2",
"GameLocation": "Rink 4 Hockey Town",
"TypeOfGame": "Tournament Round Robin",
"HomeTeam": {
"Name": "Team 1",
"ImageUrl": "My Image URL 1",
"Level": "16AAA",
"Country": "USA"
}
}, {
"GameID": 1234567890,
"GameName": "Team 1 vs Team 2",
"GameLocation": "Rink 1 Hockey Town",
"TypeOfGame": "Tournament Round Robin",
"HomeTeam": {
"Name": "Team 1",
"ImageUrl": "My Image URL 1",
"Level": "16AAA",
"Country": "USA"
}
}
]
There is no way in which you can import a JSON file and generate a custom Id in the same time. You are getting (0, 1, 2 etc) as Ids because there is no unique identifier between those objects and Firebase sees all those records as a list, and therefor provides those ids for you.
To achieve what you want, you need to add that data programmatically using the push() function provided by Firebase for each record. This method generates a unique id which easy to be used in the future.
[ {
"1234567890" : {
"GameID" : 1234567890,
"GameLocation" : "Rink 1 Hockey Town",
"GameName" : "Team 1 vs Team 2",
"HomeTeam" : {
"Country" : "USA",
"ImageUrl" : "My Image URL 1",
"Level" : "16AAA",
"Name" : "Team 1"
},
"TypeOfGame" : "Tournament Round Robin"
},
"2234567890" : {
"GameID" : 2234567890,
"GameLocation" : "Rink 4 Hockey Town",
"GameName" : "Team 3 vs Team 2",
"HomeTeam" : {
"Country" : "USA",
"ImageUrl" : "My Image URL 1",
"Level" : "16AAA",
"Name" : "Team 1"
},
"TypeOfGame" : "Tournament Round Robin"
}
} ]

Firebase fanout data to update specific fields remove other siblings fields

Each user has a conversation node, each time a new conversation has a new message I need to update both conversation nodes for the two user involved in the conversation, I want just to update the "lastMessage" and "tinestamp" fields here is my try:
let fanoutObject = [userPath : dataToUpdate,
otherUserPath : dataToUpdate]
K.FirebaseRef.root.updateChildValues(fanoutObject)
where the paths for each user is:
"/users/{userID}/conversations/{conversationID}"
and the dataToUpdate:
let dataToUpdate:[String:AnyObject] = ["timestamp" : message.timestamp,
"lastMessage": message.textBody]
Result:
The node conversations for each user is updated BUT other fields in the conversation node are removed !
the conversation node fro each user is:
"conversations" : {
"{conversationID}" : {
"lastMessage" : "your name ?",
"seen" : true,
"timestamp" : 1467849600000,
"with" : {
"country" : "US",
"firstName" : "John",
"profileImage" : "https://..."
}
}
}
note that the node conversations is inside a node user which is an element inside the root node users
and after update it's :
"conversations" : {
"{conversationID}" : {
"lastMessage" : "your name ?",
"timestamp" : 1467849600000,
}
}
but I was expecting just to update the two values and keep others ?
According to docs my code should works:
updateChildValues Update some of the keys for a defined path without
replacing all of the data.
It's a bit hard to parse your code, but most likely it's the behavior of updateChildValues() that is confusing you.
When you call updateChildValues(), the Firebase server will loop over the object that you pass in. For each path in there, it will replace the entire value at that path with the value from that you passed in.
So if your current JSON is:
{
"Users": {
"uidForUser1": {
"name": "iOSGeek",
"id": 2305342
},
"uidForUser2": {
"name": "Frank van Puffelen",
"id": 209103
}
}
And the update is (in JSON format, the lingua franca of the Firebase Database):
{
"users/uidForUser2/name": "puf",
"users/uidForUser1/name": "My actual name"
}
Your resultant JSON will be:
{
"Users": {
"uidForUser1": {
"name": "My actual name",
"id": 2305342
},
"uidForUser2": {
"name": "puf",
"id": 209103
}
}
But if you send the following update:
{
"users/uidForUser1": {
"name": "My actual name"
},
"users/uidForUser2": {
"name": "puf"
}
}
The resulting JSON will be:
{
"Users": {
"uidForUser1": {
"name": "My actual name"
},
"uidForUser2": {
"name": "puf"
}
}
Update
To update two fields in the same object, but leave the other fields unmodified:
{
"path/to/object/field1": "new value",
"path/to/object/field2": "new value2"
}
Alternatively, you can update the lastMessage and timeStamp data by replacing the old values by providing full path :
let lastMessagePath = "/users/{userID}/conversations/{conversationID}/lastMessage"
let lastTimeStampPath = "/users/{userID}/conversations/{conversationID}/timestamp"
K.FirebaseRef.child(lastMessagePath).setValue(message.timestamp)
K.FirebaseRef.child(lastTimeStampPath).setValue(message.textBody)

Trouble creating firebase data structure

For my Firebase data structure, I want it to handle something like this:
A user can create a way of logging a thought. They can call it whatever they want. Mary Chen passes the parameter journal while Mr Owner wants to name it (pass parameter) log. Firebase saves these as their own tree naming it whatever parameter the user asked to name it.
Then another tree appears: whenLoggedIn + \(parameter). This tree saves a yyyy-mm-dd date to the corresponding post.
Example:
{
"uids": {
"D0Ez8edYhIbTuUfmIeO0KOq5xVB3": {
"friends": {
"IbTuUfmIeO0KOBr5Q4gAqD": true
},
"name": "Mary Chen",
"journal": {
"entry 1- trader joes": "went to store! :)",
"entry 2- ate sushi": "took out the garbage today then got free sushi from trader joes!!!"
},
"whenLoggedInJournal": {
"1": "1997-12-25",
"2": "2016-2-23"
}
},
"L8kBHaGBr5Q4gAqDOhFY29Okepm1": {
"friends": {
"D0Ez8edYhIbTuUfmIeO0KOq5xVB3": true
},
"name": "Mr Owner",
"journal": {
"log 1": "spotted some drunkard in my store",
"log 2": "drainage pipe clogged with tomatos, I suspect the drunkard",
"log 3": "did inventory check, 1 less sushi box, suspect the drunkard"
},
"whenLoggedInLog": {
"1": "1997-12-25",
"2": "2016-2-27",
"3": "2016-4-2"
}
}
}
}
I read through "Structuring data" on the Firebase guide, but I did not grasp how to add in trees at a time. I also want to achieve a flattened data set; would that be necessary for what I am doing?
The recommended Firebase data structure is to pull up each entity to its own top-level node. So in your case that would lead to:
{
"userNames": {
"D0Ez8edYhIbTuUfmIeO0KOq5xVB3": "Mary Chen",
"L8kBHaGBr5Q4gAqDOhFY29Okepm1": "Mr Owner"
},
"userFriends": {
"D0Ez8edYhIbTuUfmIeO0KOq5xVB3": {
"IbTuUfmIeO0KOBr5Q4gAqD": true
},
"L8kBHaGBr5Q4gAqDOhFY29Okepm1": {
"D0Ez8edYhIbTuUfmIeO0KOq5xVB3": true
}
},
"userJournals": {
"D0Ez8edYhIbTuUfmIeO0KOq5xVB3": {
"entry 1- trader joes": "went to store! :)",
"entry 2- ate sushi": "took out the garbage today then got free sushi from trader joes!!!"
},
"L8kBHaGBr5Q4gAqDOhFY29Okepm1": {
"log 1": "spotted some drunkard in my store",
"log 2": "drainage pipe clogged with tomatos, I suspect the drunkard",
"log 3": "did inventory check, 1 less sushi box, suspect the drunkard"
}
},
"whenLoggedInJournals": {
"D0Ez8edYhIbTuUfmIeO0KOq5xVB3": {
"1": "1997-12-25",
"2": "2016-2-23"
},
"L8kBHaGBr5Q4gAqDOhFY29Okepm1": {
"1": "1997-12-25",
"2": "2016-2-27",
"3": "2016-4-2"
}
}
}
This structure:
makes it easier to load parts of the user data, e.g. just the names
makes it easier to secure the data, e.g. make the user names public, their friend list viewable by themselves and their friends and the journals and log-in data only viewable by themselves

Couchdb Reference Document

I'm new to CouchDB and struggling to implement a basic example. I have three documents Customer, Contact, Address and I want join them into a single document.
Account Document
{
"_id": "CST-1",
"_rev": "8-089da95f148b446bd3b33a3182de709f",
"name": "Customer",
"code": "CST-001",
"contact_Key": "CNT-001",
"address_Key": "ADD-001",
"type": "Customer"
}
Contact Document
{
"_id": "CNT-001",
"_rev": "8-079da95f148b446bd3b33a3182de709g",
"fullname": "Happy Swan",
"type": "Contact"
}
Address Document
{
"_id": "ADD-001",
"_rev": "8-179da95f148b446bd3b33a3182de709c",
"street1": "9 Glass View",
"street2": "Street 2",
"city": "USA",
"type": "Address"
}
Map/Query:
var map= function (doc) {
if (doc.type === 'Customer') {
emit(doc.id, { contact_Key: doc.contact_Key, address_Key: doc.address_Key })
}
};
db.query({ map: map }, { include_docs: true }, function (err, res) {
});
I want all 3 documents in a single document when I query account e.g.
Expected result
{
"_id": "CST-1",
"_rev": "8-089da95f148b446bd3b33a3182de709f",
"name": "Customer",
"code": "CST-001",
"contact_Key": "CNT-001",
"address_Key": "ADD-001",
"type": "Customer",
"Contact: {
"_id": "CNT-001",
"_rev": "8-079da95f148b446bd3b33a3182de709g",
"fullname": "Happy Swan",
"type": "Contact"
}",
"Address: {
"_id": "ADD-001",
"_rev": "8-179da95f148b446bd3b33a3182de709c",
"street1": "9 Glass View",
"street2": "Street 2",
"city": "USA",
"type": "Address"
}"
}
I don't see any better solution than querying the account document first and then querying the other two once you know their IDs. If you think about it, it makes sense because the only link between these documents is the IDs stored in the account document, so to get all three at the same time, internally the DB would have to do two queries: first the account document, then the other two. And by design CouchDB only does one query at a time.
If you had the account doc ID stored into the contact and address documents however, you could use a list function to merge them all into one.
First you would need a view:
function(doc) {
if (doc.type === 'Customer') {
emit(doc._id, doc);
}
if (doc.type === 'Contact' || doc.type === 'Address') {
emit(doc.account_id, doc);
}
}
Then a list function:
function(head, req) {
var row, account, contact, address;
while (row = getRow()) {
if (row.value.type === 'Customer') {
account = row.value;
} else if (row.value.type === 'Contact') {
contact = row.value;
} else if (row.value.type === 'Address') {
address = row.value;
}
}
account['Contact'] = contact;
account['Address'] = address;
provides("json", function() {
return { 'json': account };
});
}
And you would query it with:
GET /db/_design/foo/_list/the-list/the-view?key="CST-1"

Resources