I am trying to get a list of race times for females in a Firebase database that I have. I may have structured the database incorrectly but I can't see why what I am doing isn't working.
I am trying to get a list of users that are female then check what the fastest time is that matches any of the female uid's. But I am stuck with joining the tables.
My database and code looks like this:
var userref = rootref.child("Users");
var raceref = rootref.child('Races');
userref.orderByChild("Gender").equalTo('Female').on("child_added", function(snapshot) {
console.log(snapshot.key);
raceref.orderByChild("uid").equalTo(snapshot.key).once("child_added", function(raceshot) {
console.log(raceshot.key);
});
});
Then the console only shows the snapshot.key not the raceshot.key:
-864646859
-305907999
If I manually put the numbers from snapshot.key in then raceshot.key does show in the console. I don't get any errors so I am confused as to why I can't use the snapshot.key for the equalTo?
The key of a snapshot is by definition a string, so your in your /Users/$id the $id values are strings. But in the /Races/$raceid/uid property you store the value as a number.
My sense is that the comparison fails on the type. If that is indeed the cause, you should be able to fix it by converting the key to a number:
userref.orderByChild("Gender").equalTo('Female').on("child_added", function(snapshot) {
console.log(snapshot.key);
raceref.orderByChild("uid").equalTo(parseInt(snapshot.key)).once("child_added", function(raceshot) {
console.log(raceshot.key);
});
});
Related
I am currently trying to append data through I pull from Firebase to a table in the order of newest to oldest posts. I currently have the following setup in my code base (simplified to address issue):
var theDataRef = new Firebase('https://my-app.firebaseio.com');
theDataRef.orderByChild("timestamp").limitToLast(25).on('child_added', function (snapshot) {
var message = snapshot.val();
displaytableRow(message.name, message.text);
}
function displaytableRow(name, message) {
$("#sch").find('tbody > tr:first')
.before($("<tr><td><div>" + name + ":" + message + "</div></td></tr>"))
};
I have tried to create a table that displays newest to oldest data by using both firebase and jquery techniques but every time my data is displayed in a random order. I have a working timestamp field on every record in my data as well but even ordering by that does not solve the problem. Has anybody had any experience building this successfully?
EDIT:
The timestamp is gotten with the following code:
var timestamp = Firebase.ServerValue.TIMESTAMP;
And the database architecture is structured like so:
If you want to order your posts from newest to oldest you can do the following:
1/ Store a field in your post that is the inverse of the TimeStamp as follows:
var tDate = new Date().getTime();
var postData = {
//.....
timestampInverted: (0 - tDate),
//.....
};
2/ Query your posts ordered by this field as follows:
theDataRef.orderByChild("timestampInverted").limitToLast(25).once('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
displaytableRow(childSnapshot.val().name, childSnapshot.val().text);
});
});
It is important to note that theDataRef.orderByChild("timestampInverted").limitToLast(25) returns a Query, which returns a DataSnapshot : Therefore you need to use snapshot.forEach() (see doc here) to iterate over the different posts items.
Also note that "even when there is only a single match for the query, the snapshot is still a list; it just contains a single item. To access the item, you always need to loop over the snapshot".
I have some data in a directory and I want to retrieve the value of a certain object e.g. Get the value of "NVR".
Another task I need to do is have a 'for' loop to go over and get information about different questions from the following data. I would need to get the number e.g. "001" and the items inside of that subdirectory. And it would also need to go through every directory in 'questions' such as NVR or MTH.
For the first one, you can try this:
firebase.database().ref().child("unique").on('value', function(snapshot) {
var datas = snapshot.val();
var nvr=datas.NVR;
)};
For the second one try this:
firebase.database().ref().child("questions").child("NVR").on('value', function(snapshot) {
snapshot.forEach(function(child) {
var keys=child.key;
var datas = child.val();
var correcta=child.val().correctAnswer;
var num=child.val().numberOfAnswers;
//etc
});
});
the first one the snapshot will be at unique, then you will be able to retrieve the child NVR.
In the second one, you iterate inside NVR and retrieve the key using var keys=child.key;
Try something like this for going through every directory in questions and for each one getting all the questions in it :
firebase.database.ref('questions').on('value').then((snapshots) => {
//print whole questions group (nvr, mth, etc)
console.log(snapshots.val())
snapshots.forEach((snapshot) => {
//print each question in question group
console.log(snapshot.val())
})
}
Both Peter's and Egor's answers load all data under unique. Since you know the key of the item whose value you want to retrieve, you can load this more efficiently with:
firebase.database().ref("unique/NVR").on('value', function(snapshot) {
var nvr=snapshot.val();
)};
This is supposed to be a simple many to many relationships in meteor but I must be missing something because i cannot get it to work.
I have a Collection called reblog and in it is an array of integers called descovered see image
I have a second collection called posts which is a collection of posts, and these posts have an id. take a look at the second image
I want to create a many to many relationships between the posts and the reblog collection. i.e, I want to match the integer
descovered: 9
from the reblog collection, with:
id: 9
from the posts collection so that I can display only the posts matched from the reblog collection. This of course will allow me to display the title of the post and other attributes.
This is my js
Template.reblogging.helpers({
descovered() {
var id = FlowRouter.getParam('_id');
//fetch the reblog collection contents
var rebloged = reblog.find().fetch();
//log below is showing that the fetch is successful because i can see the objects fetched in console
console.log(rebloged);
//create the relationship between the posts collection and the reblog collection
var reblogger = posts.find({
id: {
$in: rebloged
}
}).fetch();
//nothing is showing with the log below, so something is going wrong with the line above?
console.log(reblogger);
return reblogger
}
});
I must be missing something because this seems a pretty straightforward thing but it's not woring
And my HTML is like this
<template name="reblogging">
{{#each descovered }}
<ul class="">
<li>
<h5 class="">{{title.rendered}}</h5>
</li>
</ul>
{{/each}}
</template>
You don't need to convert to strings and parse, you can use .map() directly on the cursor to create an array of descovered values. Also since you are using Blaze you can just return a cursor instead of an array. I suspect you also meant to use your FlowRouter _id parameter in your first .find(). If you didn't then there's no need to get that param in your helper.
Template.reblogging.helpers({
descovered() {
const id = FlowRouter.getParam('_id');
const reblogArr = reblog.find(id).map(el => { return el.descovered });
return posts.find({ id: { $in: reblogArr } });
}
);
As it turns out, the matching was accurate, however, the data from reblog collection needed to be treated with REGEX to get rid of everything else apart from the values I needed, then turn them into an array, this is the final code that worked. leaving it here, Hopefully, it will help someone in the future.
Template.reblogging.helpers({
descovered() {
var id = FlowRouter.getParam('_id');
//fetch the reblog collection contents
var rebloged = reblog.find().fetch();
//log below is showing that the fetch is successful because i can see the objects fetched in console
console.log(rebloged);
//turn it into a string so i can extract only the ids
var reblogString = JSON.stringify(rebloged).replace(/"(.*?)"/g, '').replace(/:/g, '').replace(/{/g, '').replace(/}/g, '').replace(/,,/g, ',').replace(/^\[,+/g, '').replace(/\]+$/g, '');
//after have extracted what i needed, i make it into an array
var reblogArr = reblogString.split(',').map(function(item) {
return parseInt(item, 10);
});
//create the relationship between the posts collection and the reblog collection
var reblogger = posts.find({
id: {
$in: reblogArr
}
}).fetch();
//nothing is showing with the log below, so something is going wrong with the line above?
console.log(reblogger);
return reblogger
}
});
I've looking for an answer for like 5 five hours straight, hope somebody can help. I have a MongoDb collection results (I'm using mLab) which looks like this:
{
"user":"5818be9c74aaec1824c28626"
"results":[{
"game_id":14578,
"level1":-1,
"level2":-1,
"level3":-1
},
{ ....
}],
{ "user":....
}
}
"user" is a MongoID I save in a previous part of the code, "results" is a record of scores. When an user does a new score, I have to update the score of the corresponding level (I'm using NodeJS).
This is one of the things I've tried so far.
app.get('/levelCompleted/:id/:time', function (request, response) {
var id = request.params.id;
var time = parseInt(request.params.time);
var u= game.getUserById(id);
var k = "results.$.level"+(u.level);
//I build the key to update dinamycally
dbM.collection("results").update(
{user:id,
"results.game_id":u.game_id
//u has its own game_id
},
{$set: {k:time}}
);
...
response.send(...);
});
I've checked the content of every variable and parameter, tried also using $elemMatch and dot notation, set upsert and multi, with no results. I've used an identical command on mongo shell and it has work on the first try.
Update with Mongo Shell
If someone could tell me what I'm doing wrong or point me in the right direction, it would be great.
Thanks
When you use a MongoId as a field in a MongoDB, you can't just pass a string with the id to do the query, you have to identify that string as an ObjectId (Id type in Mongo). Just add a new require in your node.js file.
var ObjectID = require("mongodb").ObjectID;
And use the imported constructor in your update request.
dbM.collection("results").update(
{user:ObjectID(id),...
...
}
Currently, I have a table named Appointments- on appointments, I have a Relation of Clients.
In searching the parse documentation, I haven't found a ton of help on how to eagerly fetch all of the child collection of Clients when retrieving the Appointments. I have attempted a standard query, which looked like this:
var Appointment = Parse.Object.extend("Appointment");
var query = new Parse.Query(Appointment);
query.equalTo("User",Parse.User.current());
query.include('Rate'); // a pointer object
query.find().then(function(appointments){
let appointmentItems =[];
for(var i=0; i < appointments.length;i++){
var appt = appointments[i];
var clientRelation = appt.relation('Client');
clientRelation.query().find().then(function(clients){
appointmentItems.push(
{
objectId: appt.id,
startDate : appt.get("Start"),
endDate: appt.get("End"),
clients: clients, //should be a Parse object collection
rate : appt.get("Rate"),
type: appt.get("Type"),
notes : appt.get("Notes"),
scheduledDate: appt.get("ScheduledDate"),
confirmed:appt.get("Confirmed"),
parseAppointment:appt
}
);//add to appointmentitems
}); //query.find
}
});
This does not return a correct Clients collection-
I then switched over to attempt to do this in cloud code- as I was assuming the issue was on my side for whatever reason, I thought I'd create a function that did the same thing, only on their server to reduce the amount of network calls.
Here is what that function was defined as:
Parse.Cloud.define("GetAllAppointmentsWithClients",function(request,response){
var Appointment = Parse.Object.extend("Appointment");
var query = new Parse.Query(Appointment);
query.equalTo("User", request.user);
query.include('Rate');
query.find().then(function(appointments){
//for each appointment, get all client items
var apptItems = appointments.map(function(appointment){
var ClientRelation = appointment.get("Clients");
console.log(ClientRelation);
return {
objectId: appointment.id,
startDate : appointment.get("Start"),
endDate: appointment.get("End"),
clients: ClientRelation.query().find(),
rate : appointment.get("Rate"),
type: appointment.get("Type"),
notes : appointment.get("Notes"),
scheduledDate: appointment.get("ScheduledDate"),
confirmed:appointment.get("Confirmed"),
parseAppointment:appointment
};
});
console.log('apptItems Count is ' + apptItems.length);
response.success(apptItems);
})
});
and the resulting "Clients" returned look nothing like the actual object class:
clients: {_rejected: false, _rejectedCallbacks: [], _resolved: false, _resolvedCallbacks: []}
When I browse the data, I see the related objects just fine. The fact that Parse cannot eagerly fetch relational queries within the same call seems a bit odd coming from other data providers, but at this point I'd take the overhead of additional calls if the data was retrieved properly.
Any help would be beneficial, thank you.
Well, in your Cloud code example - ClientRelation.query().find() will return a Parse.Promise. So the output clients: {_rejected: false, _rejectedCallbacks: [], _resolved: false, _resolvedCallbacks: []} makes sense - that's what a promise looks like in console. The ClientRelation.query().find() will be an async call so your response.success(apptItems) is going to be happen before you're done anyway.
Your first example as far as I can see looks good though. What do you see as your clients response if you just output it like the following? Are you sure you're getting an array of Parse.Objects? Are you getting an empty []? (Meaning, do the objects with client relations you're querying actually have clients added?)
clientRelation.query().find().then(function(clients){
console.log(clients); // Check what you're actually getting here.
});
Also, one more helpful thing. Are you going to have more than 100 clients in any given appointment object? Parse.Relation is really meant for very large related collection of other objects. If you know that your appointments aren't going to have more than 100 (rule of thumb) related objects - a much easier way of doing this is to store your client objects in an Array within your Appointment objects.
With a Parse.Relation, you can't get around having to make that second query to get that related collection (client or cloud). But with a datatype Array you could do the following.
var query = new Parse.Query(Appointment);
query.equalTo("User", request.user);
query.include('Rate');
query.include('Clients'); // Assumes Client column is now an Array of Client Parse.Objects
query.find().then(function(appointments){
// You'll find Client Parse.Objects already nested and provided for you in the appointments.
console.log(appointments[0].get('Clients'));
});
I ended up solving this using "Promises in Series"
the final code looked something like this:
var Appointment = Parse.Object.extend("Appointment");
var query = new Parse.Query(Appointment);
query.equalTo("User",Parse.User.current());
query.include('Rate');
var appointmentItems = [];
query.find().then(function(appointments){
var promise = Parse.Promise.as();
_.each(appointments,function(appointment){
promise = promise.then(function(){
var clientRelation = appointment.relation('Clients');
return clientRelation.query().find().then(function(clients){
appointmentItems.push(
{
//...object details
}
);
})
});
});
return promise;
}).then(function(result){
// return/use appointmentItems with the sub-collection of clients that were fetched within the subquery.
});
You can apparently do this in parallel, but that was really not needed for me, as the query I'm using seems to return instantaniously. I got rid of the cloud code- as it didnt seem to provide any performance boost. I will say, the fact that you cannot debug cloud code seems truly limiting and I wasted a bit of time waiting for console.log statements to show themselves on the log of the cloud code panel- overall the Parse.Promise object was the key to getting this to work properly.