Firebase query with variables in Swift - database

I'm trying to find specific user images from my Firebase data set I'm naming the group users with unique display names as children and those children with keys of name, lowerCaseName, UID, and Image.
Is there anyway I can query through users as a variable in order to get to images?? I'm thinking http://firebase.com/users/%diplaynames/image but not sure.

What is your Firebase base url? You should be querying the path that looks something like:
https://<APP ID HERE>.firebaseio.com/
So you're initialization of Firebase should look like:
let fire = Firebase(url: "https://<APP ID HERE>.firebaseio.com/users/<DISPLAYNAME>/image")
Alternatively, you could do:
let fire = Firebase(url: "https://<APP ID HERE>.firebaseio.com")
let imageRef = fire.childByAppendingPath("users").childByAppendingPath("<DISPLAYNAME>).childByAppendingPath("image")

In Firebase, you cannot retrieve a subset of the properties of a node. Either a node is retrieved, or it isn't.
If you have a use-case where you need to retrieve just the images, you should store a top-level node that has just those images.
userImages
Charles: base64data
Zach: base64data

A couple of thoughts:
While there is nothing wrong with your structure, you may want to consider changing the node names from the users name to a firebase auto generated ID.
users
user_0
name: Charles
image: some image
user_1
name: Zaddy
image: another image
Sometimes data will change, so for example say Charles wants to be called Charlie. To make that change you would have to delete the Charles node*, re-add it, and then update every node that refers back to Charles. If you name it with an auto-generated id (or the uid; best practice) user_0, then just update the name: "Charlie" and everything else falls into place.
*The child name: and the node name can certainly be the same or different, so this is a situational example.
To get Charles' image (assuming it's base64 encoded) and you want to add it to an imageView
let ref = Firebase(url:"https://your_app.firebaseio.com/users")
ref.queryOrderedByChild("name").queryEqualToValue("Charles")
.observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
//snapshot will contain the child key/value pairs
let base64EncodedString = snapshot.value.objectForKey("image")
let imageData = NSData(base64EncodedString: base64EncodedString as! String, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
let decodedImage = NSImage(data:imageData!)
self.myImageView.image = decodedImage
})

Related

Adding data to nested collection firebase cloud firestore

Right now my firebase cloud firestore looks like this:
const db = fire.firestore();
db.collection("groupFavs/"+groupID+ "/"+currentUserUID).add({favs: likedData})
The code above creates a collection called groupFavs, a document called groupID and another collection with the current users id. In the image I have above, it keeps creating documents for the users likes when i just want the currentuser id to only have one list in it which will be all their liked data. But instead it just keeps making multiple of them and I think its because of .add
I've tried using set but that wont work. Where am I going wrong?
db.collection("groupFavs2")
.doc(groupID).collection(currentUserUID)
.set({
favs: likedData
})
I basically want to do something like this above but my logic is off in regards to the nested collection because what im calling above does not work
You can circumvent the string concatenation as well as the nested .collection .doc chain by using string interpolation as follows:
const collectionRef = db.collection(`groupFavs/${groupID}/${currentUserUID}`)
collectionRef.add({favs: likedData})
In regards to the multiple documents, you are adding a new document under the sub collection (matching the users id). Ideally this would look something like this:
Group Favs
1st UserId
Like 1 doc
Like 2 doc
2st UserId
Like 1 doc
Like 2 doc
Where the like doc can contain information related to the like such as image or liked boolean property.
If instead what you would like to do is keep a list of the users likes under their doc you can do it as follows:
const docRef= db.doc(`groupFavs/${groupID}/${currentUserUID}`)
const newLikeData = {
likes: firestore.FieldValue.arrayUnion(<your_like_information>)
}
docRef.set({favs: likedData}, {merge:true})
arrayUnion will append whatever data is in <your_like_information>.
Alternatively, you could query for the current likes list under the users doc, manually append the information and pass the entire object to a update or setDoc with merge: true.

How to Fetch a set of Specific Keys in Firebase?

Say I'd like to fetch only items that contains keys: "-Ju2-oZ8sJIES8_shkTv", "-Ju2-zGVMuX9tMGfySko", and "-Ju202XUwybotkDPloeo".
var items = new Firebase("https://hello-cambodia.firebaseio.com/items");
items.orderByKey().equalTo("-Ju2-gVQbXNgxMlojo-T").once('value', function(snap1){
items.orderByKey().equalTo("-Ju2-zGVMuX9tMGfySko").once('value', function(snap2){
items.orderByKey().equalTo("-Ju202XUwybotkDPloeo").once('value', function(snap3){
console.log(snap1.val());
console.log(snap2.val());
console.log(snap3.val());
})
})
});
I don't feel that this is the right way to fetch the items, especially, when I have 1000 keys over to fetch from.
If possible, I really hope for something where I can give a set of array
like
var itemKeys = ["-Ju2-gVQbXNgxMlojo-T","-Ju2-zGVMuX9tMGfySko", "-Ju202XUwybotkDPloeo"];
var items = new Firebase("https://hello-cambodia.firebaseio.com/items");
items.orderByKey().equalTo(itemKeys).once('value', function(snap){
console.log(snap.val());
});
Any suggestions would be appreciated.
Thanks
Doing this:
items.orderByKey().equalTo("-Ju2-gVQbXNgxMlojo-T")
Gives exactly the same result as:
items.child("-Ju2-gVQbXNgxMlojo-T")
But the latter is not only more readable, it will also prevent the need for scanning indexes.
But what you have to answer is why want to select these three items? Is it because they all have the same status? Because they fell into a specific date range? Because the user selected them in a list? As soon as you can identify the reason for selecting these three items, you can look to convert the selection into a query. E.g.
var recentItems = ref.orderByChild("createdTimestamp")
.startAt(Date.now() - 24*60*60*1000)
.endAt(Date.now());
recentItems.on('child_added'...
This query would give you the items of the past day, if you had a field with the timestamp.
You can use Firebase child. For example,
var currFirebaseRoom = new Firebase(yourFirebaseURL)
var userRef = currFirebaseRoom.child('users');
Now you can access this child with
userRef.on('value', function(userSnapshot) {
//your code
}
You generally should not be access things using the Firebase keys. Create a child called data and put all your values there and then you can access them through that child reference.

How to get Entry Id for a Newly Created Entity in Breeze

i want to create a registration form that will be in batch with a continuation button, getting the id of the entry will help me to call the save method.
I want to immediately get the primary key of a new Entry Created using BreezeJS, Pls i need help on this.
Thanks
Not entirely sure I understand your question, but it sounds like you want to get the id of a newly saved record immediately after the save. If so then the answer below applies.
When the save promise resolves it returns both the list of saved entities as well as a keyMappings array for any entities whose ids changed as a result of the save. i.e. a mapping from temporary to real ids. i.e. (Documented here: http://www.breezejs.com/sites/all/apidocs/classes/EntityManager.html#method_saveChanges)
myEntityManager.saveChanges().then(function (saveResult) {
// entities is an array of entities that were just saved.
var entitites = saveResult.entities;
var keyMappings = saveResult.keyMappings;
keyMappings.forEach(function(km) {
var tempId = km.tempValue;
var newId = km.realValue;
});
});
On the other hand if you have an entity and you just want its 'key' you can use the EntityAspect.getKey method. (see http://www.breezejs.com/sites/all/apidocs/classes/EntityAspect.html#method_getKey)
// assume order is an order entity attached to an EntityManager.
var entityKey = order.entityAspect.getKey();

AngularFire - How do I query denormalised data?

Ok Im starting out fresh with Firebase. I've read this: https://www.firebase.com/docs/data-structure.html and I've read this: https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html
So I'm suitably confused as one seems to contradict the other. You can structure your data hierarchically, but if you want it to be scalable then don't. However that's not the actual problem.
I have the following structure (please correct me if this is wrong) for a blog engine:
"authors" : {
"-JHvwkE8jHuhevZYrj3O" : {
"userUid" : "simplelogin:7",
"email" : "myemail#domain.com"
}
},
"posts" : {
"-JHvwkJ3ZOZAnTenIQFy" : {
"state" : "draft",
"body" : "This is my first post",
"title" : "My first blog",
"authorId" : "-JHvwkE8jHuhevZYrj3O"
}
}
A list of authors and a list of posts. First of all I want to get the Author where the userUid equals my current user's uid. Then I want to get the posts where the authorId is the one provided to the query.
But I have no idea how to do this. Any help would be appreciated! I'm using AngularFire if that makes a difference.
Firebase is a NoSQL data store. It's a JSON hierarchy and does not have SQL queries in the traditional sense (these aren't really compatible with lightning-fast real-time ops; they tend to be slow and expensive). There are plans for some map reduce style functionality (merged views and tools to assist with this) but your primary weapon at present is proper data structure.
First of all, let's tackle the tree hierarchy vs denormalized data. Here's a few things you should denormalize:
lists you want to be able to iterate quickly (a list of user names without having to download every message that user ever wrote or all the other meta info about a user)
large data sets that you view portions of, such as a list of rooms/groups a user belongs to (you should be able to fetch the list of rooms for a given user without downloading all groups/rooms in the system, so put the index one place, the master room data somewhere else)
anything with more than 1,000 records (keep it lean for speed)
children under a path that contain 1..n (i.e. possibly infinite) records (example chat messages from the chat room meta data, that way you can fetch info about the chat room without grabbing all messages)
Here's a few things it may not make sense to denormalize:
data you always fetch en toto and never iterate (if you always use .child(...).on('value', ...) to fetch some record and you display everything in that record, never referring to the parent list, there's no reason to optimize for iterability)
lists shorter than a hundred or so records that you always as a whole (e.g. the list of groups a user belongs to might always be fetched with that user and would average 5-10 items; probably no reason to keep it split apart)
Fetching the author is as simple as just adding the id to the URL:
var userId = 123;
new Firebase('https://INSTANCE.firebaseio.com/users/'+userId);
To fetch a list of posts belonging to a certain user, either maintain an index of that users' posts:
/posts/$post_id/...
/my_posts/$user_id/$post_id/true
var fb = new Firebase('https://INSTANCE.firebaseio.com');
fb.child('/my_posts/'+userId).on('child_added', function(indexSnap) {
fb.child('posts/'+indexSnap.name()).once('value', function(dataSnap) {
console.log('fetched post', indexSnap.name(), dataSnap.val());
});
});
A tool like Firebase.util can assist with normalizing data that has been split for storage until Firebase's views and advanced querying utils are released:
/posts/$post_id/...
/my_posts/$user_id/$post_id/true
var fb = new Firebase('https://INSTANCE.firebaseio.com');
var ref = Firebase.util.intersection( fb.child('my_posts/'+userId), fb.child('posts') );
ref.on('child_added', function(snap) {
console.log('fetched post', snap.name(), snap.val();
});
Or simply store the posts by user id (depending on your use case for how that data is fetched later):
/posts/$user_id/$post_id/...
new Firebase('https://INSTANCE.firebaseio.com/posts/'+userId).on('child_added', function(snap) {
console.log('fetched post', snap.name(), snap.val());
});

Knockoutjs how to data-bind observable array members based on IDs

I'm not if the title explains what I need to achieve or not but I can change it later if some has a better suggestion.
I'm using KO to manage a whole bunch of data on the client side.
Here's the basic.
I have a list of training sessions
Each has a list of training session parts
Each training session parts are referencing items kept in other lists. For example, I have a list of activities (ex: biking, running, swimming, etc.)
Each activity is identified by an ID which is used in the training session parts to identify which activity was used for a particular session.
Now, all these list are stored as observable arrays, and each member of the lists are observables (I use KO.Mapping to map the JSON coming from the server)
When I display a training session in my UI, I want to display various information coming from various lists
Duration: 1h30
Activity: Biking
Process: Intervals
The only information I have in order to link the training session to its component is an ID which is fine. What I'm not sure is how to data-bind the name (text) of my activity to a <p> or <div> so that the name will change if I edit the activity (by using some functionality of the application).
The training session only has the ID to identify the activity, so I don’t know how to bind the name of the activity based on its ID.
Hopefully this makes senses and someone can help me figure it out. I found lots of info on how to bind to observable array but nothing addressing ID and linked information.
The easiest way would probably be to make your own constructors and link the data by hand. You can use mapping if you really want to, but you'll basically have to do the same manual linking, only in a more verbose format.
This is the fiddle with the example implementation: http://jsfiddle.net/aKpS9/3/
The most important part of the code is the linking, you have to take care to create the activity objects only once, and use the same objects everywhere, as opposed to creating new activity objects for the parts.
var TrainingSession = function(rawData, actualActivities){
var self = this;
self.name = ko.observable(rawData.name);
self.parts = ko.observableArray(ko.utils.arrayMap(rawData.parts, function(rawPart){
return ko.utils.arrayFirst(actualActivities(), function(ac){
return ac.ID() == rawPart.ID;
})
}));
}
var Activity = function(rawData){
var self = this;
self.ID = ko.observable(rawData.ID);
self.name = ko.observable(rawData.name);
}
var MainVM = function(rawData){
var self = this;
//first create an array of all activities
self.activities = ko.observableArray(ko.utils.arrayMap(rawData.activities, function(rawAc){
return new Activity(rawAc);
}));
self.trainingSessions = ko.observableArray(ko.utils.arrayMap(rawData.trainingSessions, function(session){
return new TrainingSession(session, self.activities);
}));
}

Resources