I'm trying to fetch all flowers data which belongs to a certain user, in this case simplelogin:69.
I'm starting with fetching all flower keys from the user, like this:
/users/simplelogin:69/flowers/
var ref = new Firebase("https://URL.firebaseio.com/users/"+uid+"/flowers");
var sync = $firebase(ref);
Now im stuck figuring out a clean way to fetch all the flower data by looping thrue every flower key from simplelogin:69 without looping thrue EVERY key in /flowers/ (in example below i only have three flower keys but in production i might have 10k).
I tried FirebaseIndex and firebase-util, but can't get it to work properly. Do anyone have any tips or anything? I've read previous posts here on stack but most seems out of date or not really suited for what im going for. Would really appriciate anything that can be solved with AngularFire.
Kind regards,
Elias
{
"flowers" : {
"-JiU57sFAfQwYtIq-LCl" : {
"image" : "test",
"name" : "test",
"type" : "Roses",
"uid" : "simplelogin:69"
},
"-JiU9-3ajlnFLpyUmBvL" : {
"image" : "dasdasd",
"name" : "sadasdas",
"type" : "Roses",
"uid" : "simplelogin:69"
},
"-JiUF-mioK3jQCYy6ZiG" : {
"image" : "ss",
"name" : "ss",
"type" : "Lilies",
"uid" : "simplelogin:69"
}
},
"users" : {
"simplelogin:69" : {
"flowers" : {
"-JiU57sFAfQwYtIq-LCl" : true,
"-JiU9-3ajlnFLpyUmBvL" : true,
"-JiUF-mioK3jQCYy6ZiG" : true
}
},
"simplelogin:70" : {
},
"simplelogin:71" : {
}
}
}
Got it to work now, thanks to #Kato 's answer on thread:
Firebase data normalized. How should I fetch a collection based on this structure? (tried it before creating this thread but didnt get it to work, so made som small changes and now it works).
Posting the solution for anyone stubling upon the same situation:
$scope.flowers = {};
var flowerRef = new Firebase('https://URL.firebaseio.com/flowers/');
var keyRef = new Firebase('https://URL.firebaseio.com/users/'+checkAuth.auth.uid+'/flowers');
keyRef.on('child_added', function(snap) {
var flowerId = snap.key();
flowerRef.child(flowerId).on('value', function(snap) {
$timeout(function() {
if( snap.val() === null ) {
delete $scope.flowers[flowerId];
}
else {
$scope.flowers[flowerId] = snap.val();
}
});
});
});
keyRef.on('child_removed', function(snap) {
var flowerId = snap.key();
$timeout(function(snap) {
delete $scope.flowers[flowerId];
});
});
This really is a tough issue with Firebase. If you implement a custom factory object for the user's flower list, you could dynamically request new flower data as the list changes.
Related
I'm fairly new to meteor and I'm still trying to find my way around with filtering collections. Here is my problem, I have a collection defined as follows;
parent_id: {
label: 'Parent ID',
type: String,
},
ar_session_id: {
label: 'Session ID',
type: String,
},
I have inserted some documents and here is one;
{
"_id" : "oQdtbBtKXHzdxWvzn",
"parent_id" : "dJkbDBXut5WzwkaFN",
"ar_session_id" : "dJkbDBXut5WzwkaFNuz77MFgcuGyvgokip",
"question" : "Do you have blah blah...?",
"answer" : "no",
"createdAt" : 1564563509127
}
I am able to filter using parent_id but I can't filter using ar_session_id
var parent_id = "dJkbDBXut5WzwkaFN";
var ar_session_id = "dJkbDBXut5WzwkaFNuz77MFgcuGyvgokip";
qry1 = AssessmentResponse.find({parent_id: parent_id}).fetch();
qry2 = AssessmentResponse.find({ar_session_id: ar_session_id}).fetch();
qry2 returns an empty set. What is it that I am missing?
The only reason I could think of would be if you are not publishing ar_session_id in the client.
For instance if you had something like this:
Meteor.publish("AssessmentResponse", function () {
return AssessmentResponse.find({}, { fields: { ar_session_id: 0 } });
});
Otherwise there is no reason the filtering would be empty, assuming you don't have any typo.
I have a collection in firebase real time database that is a pool of codes that can be used once per 'store'. I need to search for an unused code, then mark it reserved by a store in an atomic fashion. The problem is I can't figure out how to do a transactional search and update in firebase, and the unused code is being 'used' multiple times until it gets updated.
const getUnusedCode = (storeID) => {
const codeRef = rtdb.ref('codes');
return codeRef
.orderByChild(storeID)
.equalTo(null)
.limitToFirst(1)
.once('child_added')
.then(snap => {
//setting the map {[storeID]:true} reserves the code
return snap.ref.update({ [storeID]: true }).then(() => {
return snap.key;
});
});
};
Edit: Here is the structure of the 'codes' collection:
{
"-LQl9FFD39PAeN5DnrGE" : {
"code" : 689343821901,
"i" : 0,
"5s6EgdItKW7pBIawgulg":true,
"ZK0lFbDnXcWJ6Gblg0tV":true,
"uKbwxPbZu2fJlsn998vm":true
},
"-LQl9FOxT4eq6EbwrwOx" : {
"code" : 689343821918,
"i" : 1,
"5s6EgdItKW7pBIawgulg":true
},
"-LQl9FPaUV33fvkiFtv-" : {
"code" : 689343821925,
"i" : 2
},
"-LQl9FQEwKKO9T0z4LIP" : {
"code" : 689343821932,
"i" : 3,
"ZK0lFbDnXcWJ6Gblg0tV":true
},
"-LQl9FQsEVSNZyhgdHmI" : {
"code" : 689343821949,
"i" : 4,
"5s6EgdItKW7pBIawgulg":true,
"uKbwxPbZu2fJlsn998vm":true
}
}
In this data, "5s6EgdItKW7pBIawgulg" is a store id, and true means this code has been used for this store
When new items are being imported, this function may get called hundres of times a minute, and is returning duplicates since it's not an atomic search-then-update. Is this possible in Firebase?
From what I understand you have a structure like this
codes: {
"code1": {
storeid: "store1"
},
"code2": {
storeid: "store2"
}
}
And you're trying to transactionally update it per store.
If this is the only update you're trying to do, I'd highly recommend inverting your data structure:
codes: {
"store1": "code1",
"store2": "code2"
}
On this structure the transaction for a store is quite simple, since the path is known:
var storeRef = firebase.database().ref("codes").child("store1");
storeRef.transation(function(current) {
if (current) {
// remove the code from the database
return null;
}
else {
// abort the transaction, since the code no longer exists
return undefined;
}
});
If you can't change the data structure, I'd probably user your current code to find the DatabaseReference to the code, and then use a transaction within the callback to update:
codeRef
.orderByChild(storeID)
.equalTo(null)
.limitToFirst(1)
.once('child_added')
.then(snap => {
//setting the map {[storeID]:true} reserves the code
return snap.ref.transaction(function(current) {
if (!current || current[storeId]) {
// the node no longer exists, or it already was claimed for this store
return undefined; // abort the transaction
}
else {
current[storeId] = true;
return current;
}
})
});
This question already has answers here:
Firebase search by child value
(2 answers)
Closed 3 years ago.
{
"users" : {
"1320104182" : {
"datas" : {
"bio" : "some_data",
"picture" : "some_data",
"username" : "some_data",
"website" : "some_data",
"followers" : 14,
}
},
"3271376571" : {
"datas" : {
"bio" : "some_data",
"picture" : "some_data",
"username" : "some_data",
"website" : "some_data",
"followers" : 10,
}
}
}
}
I'm new to Firebase and i'm trying to do multiple think here without any success so far.
How can i retrieve a user by his "username" without knowing the key ?
Or how can i order the users by followers ?
I tried everything i could find in the documentation for a few hours i'm desperate.
This seems fairly easy:
var ref = firebase.database().ref("users");
var query = ref.orderByChild("database/username").equalTo("some_data");
query.once("value", function(snapshot) {
snapshot.forEach(function(child) {
console.log(child.key, child.val().bio);
});
});
Firebase is not so good when you need fancy queries. You must handle everything in your client (JavaScript) which is not the best approach when dealing with large data. In this case, I'd suggest you something like this:
const nameToSearch = 'John';
firebase.ref('users').once('value') //get all content from your node ref, it will return a promise
.then(snapshot => { // then get the snapshot which contains an array of objects
snapshot.val().filter(user => user.name === nameToSearch) // use ES6 filter method to return your array containing the values that match with the condition
})
To order by followers, you can either also apply sort() (see example 1) or any of firebase default methods orderByChild() (see example 2), orderByKey (see example 3), or orderByValue (see example 4)
Example 1:
firebase.database().ref("users").once('value')
.then(snapshot => {
const sortedUsers = snapshot.sort((userA, userB) => {
if (userA.name < userB.name) {
return -1;
}
if (userA.name > userB.name) {
return 1;
}
return 0;
})
})
Example 2:
var ref = firebase.database().ref("dinosaurs");
ref.orderByChild("height").on("child_added", function(snapshot) {
console.log(snapshot.key + " was " + snapshot.val().height + " m tall");
});
Example 3:
var ref = firebase.database().ref("dinosaurs");
ref.orderByKey().on("child_added", function(snapshot) {
console.log(snapshot.key);
});
Example 4:
var scoresRef = firebase.database().ref("scores");
scoresRef.orderByValue().limitToLast(3).on("value", function(snapshot) {
snapshot.forEach(function(data) {
console.log("The " + data.key + " score is " + data.val());
});
});
Note: there might be typos in the examples, I wrote just to show you the idea of the concepts.
Check the following docs for more info:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://firebase.google.com/docs/reference/js/firebase.database.Query#orderByChild
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Hope it helps
I have the following structure:
{
"Campaign" : {
"-KtghP_NMOFrjN_RrI6f" : {
"Projects" : {
"-Kz5g4j8dKgxtqQsPfN1" : {
"createByName" : "Michal",
"profileId" : "-KtlDwI3Bq4Bi7R23kya"
},
"-KzGCaLblTxzu4Nje15Z" : {
"createByName" : "Roy",
"profileId" : "-Kxx_egu9h4GOrxqM1nB"
}
}
},
"-KyjE0HPNSg27Kpurq8l" : {
"Projects" : {
"-KzBUZBsI947HckV296O" : {
"createByName" : "Roy",
"profileId" : "-Kxx_egu9h4GOrxqM1nB"
}
}
}
},
"UserProfile" : {
"-Kxx_egu9h4GOrxqM1nB" : {
"MyProjects" : {
"-KzGC3Yn4bAAorcwDhUT" : {
"CampaignId" : "-KyjE0HPNSg27Kpurq8l",
"projectId" : "-KzBUZBsI947HckV296O"
},
"-KzGCaeTqMm_g1Jq6u6i" : {
"CampaignId" : "-KtghP_NMOFrjN_RrI6f",
"projectId" : "-KzGCaLblTxzu4Nje15Z"
}
},
"firstName" : "roy"
}
}
}
i have the profile id.
I need to get the different projects of the user, under the different Campaigns..
I want to get the list of MyProjects by the userid, and then iterate (with the keys i got from MyProjects) over the campaigns -(key)-> projects -(key)-> profileId and compare them...
(hope it was clear enough...)
HOW DO I DO THAT?
Ok, after some more research, i went a different way.
it seems like i don't need "MyProjects".
var userId = "-Kxx_egu9h4GOrxqM1nB";
var campaignRef = this.db.app.database().ref('Campaign'); //root
var projectsRef = campaignRef.child('Projects');
projectsRef.orderByChild('profileId').equalTo(userId).once("value", (snap) => {
console.log(snap.val());
});
but still i get NULL..
(tried "child_added" and .on in different combinations - nothing...)
After logging in, and pulling the Campaign object, you can try running the following code:
// user is an object from the userProfile. You can also just directly access the object and get what you need. Really, it's up to you. I'll assume that you also stored the user ID (uid) here too.
var user = {},
campaigns = {},
uid = {},
myProjects = [];
function getProjects() {
for (var i in campaigns) {
for (var k in campaigns[i]) {
// Make sure that the profileId of the project and the uid match, then push object into myProjects array
campaigns[i][k].profileId === uid ? myProjects.push(campaigns[i][k]) : 'nada';
}
}
}
In the myProjects array will you find your projects.
I use Firebase and AngularFire4 in a web application. The model is relatively simple, but I am having troubles in finding the right way to design it.
I have two collections: places and countries like the following:
Places
"places" : {
"-Kjx7NhHnyZNIZbxvzx4" : {
"name" : "Dereck beer",
"type" : "Bar"
"location" : {
"cityName" : "Kagoshima",
"country" : {
"code" : "JP",
"id" : 110,
"name" : "Japan"
},
"streetName" : "892-0842 Higashisen"
},
"modifiedOn": 121211321321
}
//... More data here...
}
Countries
"countries" : {
"110" : {
"code" : "JP",
"id" : 110,
"name" : "Japan"
}
}
At the moment in the web application I display the list of places and I can navigate to the detail view of each place. I can also display the countries where the places belong to (I create a new entry in countries collection, if not existing already, when a new place is created/updated).
However I would like to filter the places by some properties, like by type for instance. I tried with the following query, from AngularFire docs, but it does not work:
constructor(private db: AngularFireDatabase) {
var query = {
orderByChild: 'modifiedOn',
equalTo: {
value: 'Bar',
key: 'type' }
};
this.db.list("/places", query).subscribe( data => {
//All places are returned, and not only the one of type = "Bar"
});
}
If possible, I would like to avoid this approach and to replicate excessively my collections just for being able to query them.
it should be
var query = {
orderByChild: 'type',
equalTo: 'Bar'
};
orderByChild and equalTo is a pair in firebase, it's different from sql query