I have this Firebase database with the following data:
Here is a part of the JSON file:
"SWPL6X" : {
"-LznFoTKvdc5318O97h_" : {
"direction" : "in",
"excluded" : false,
"in" : 422,
"multiplier_out" : 1.05,
"name" : "MaM.OUT.90F8",
"out" : 6582,
"total" : -6160
},
"-M2ZQU2azNc-JTKKXojU" : {
"direction" : "in",
"excluded" : false,
"in" : 316,
"multiplier_out" : 1.05,
"name" : "CdG.Out.96A4",
"out" : 2509,
"total" : -2193
},
"-M3zVSWzqb4TaezY1Kua" : {
"direction" : "in",
"excluded" : false,
"in" : 4806,
"name" : "MaM.in.3FBC",
"out" : 748,
"total" : 4058
},
I just need to order alphabetically the last children by the field "name" (String) but I can't find a way to achieve it.
The code before I tried to sort is the following:
getSensors: function(uid, event_id, success){
var ref=firebase.database().ref('clients_events_sensors/'+ uid+ '/'+ event_id);
kap.firebase.bindings.liveObject(ref, success, function(e){
kap.log('cant get client event sensors', e)
});
},
I tried changing the first line to this with no effect:
var ref=firebase.database().ref('clients_events_sensors/'+ uid+ '/'+ event_id).orderByChild('name');
This function is only called once here, the logs retrieved keep the same order as the one coming initially from Firebase:
app.data.getSensors(kap.page.uid, kap.page.event_id, function(sensors) {
$.each(sensors, function(k, sensor){
//remove picture to avoid blowing localstorage memory
sensor.photo=null;
//Replace total by in+out/2 in the app only
sensor.total = Math.round((sensor.in+sensor.out) / 2);
sensor.sum = sensor.in+sensor.out;
});
kap.log('got sensors', sensors);
kap.page.sensors = sensors;
kap.page.fill();
});
The log:
got sensors {
"-LznFoTKvdc5318O97h_":{"direction":"in","excluded":false,"in":492,"multiplier_out":1.05,"name":"MaM.OUT.90F8","out":6983,"total":3738,"photo":null,"sum":7475},
"-M2ZQU2azNc-JTKKXojU":{"direction":"in","excluded":false,"in":339,"multiplier_out":1.05,"name":"CdG.Out.96A4","out":2686,"total":1513,"photo":null,"sum":3025},
"-M3zVSWzqb4TaezY1Kua":{"direction":"in","excluded":false,"in":5150,"name":"MaM.in.3FBC","out":836,"total":2993,"photo":null,"sum":5986},
"-M9Y7Ed7JtPSKTUQXRhd":{"direction":"in","excluded":false,"in":470,"multiplier_out":1.05,"name":"Volt.Out.99CE","out":2323,"total":1397,"photo":null,"sum":2793},
"-MAa2FZ5z5fMejpSL7zp":{"direction":"in","excluded":false,"in":4615,"multiplier_in":1,"name":"CdG.In_A011","out":486,"total":2551,"photo":null,"sum":5101},
"-MAa2QX5rvjWlT_2z7YQ":{"direction":"in","excluded":false,"in":3729,"name":"Volt.In_A013","out":1203,"total":2466,"photo":null,"sum":4932},
"-MAa2UaqVDyxQrQojFiR":{"direction":"in","excluded":false,"in":400,"multiplier_out":1.05,"name":"Pagnol.Out_A014","out":2205,"total":1303,"photo":null,"sum":2605},
"-MBiKvKAAWQkU8RABWR0":{"direction":"in","excluded":false,"in":2613,"name":"Pagnol.In_A015","out":987,"total":1800,"photo":null,"sum":3600}}
Am I missing something?
Related
I am trying to filter firebase data using startAt and/or endAt.
My data is structured as below.
{
"notes" : {
"-LOs0Ikx4ydM5RatREM1" : {
"data" : {
"dueDate" : 1561629600000,
"description" : "Korewa nan desuka?!",
"createdAt" : 1539611900000,
"title" : "First "
},
"members" : {
"author" : "1212121212121212121212121212"
}
},
"-LOs0Ikx4ydM5RatREM2" : {
"data" : {
"dueDate" : 4004870448000,
"description": "Test"
"createdAt" : 1539611900000,
"title" : "Second"
},
"members" : {
"author" : "1212121212121212121212121212"
}
},
"-LhBt9msLFKqUQ-koI9W" : {
"data" : {
"dueDate" : 1564653600000,
"description" : "abc",
"createdAt" : 1560363158279,
"title" : "August 1"
},
"members" : {
"author" : "3434343434343434343434343434"
}
},
"-LhBtKdDrQv9eKuYdfCi" : {
"data" : {
"dueDate" : 1564653600000,
"description" : "abcdef",
"createdAt" : 1560363158279,
"title" : "August 2"
},
"members" : {
"author" : "3434343434343434343434343434"
}
}
}
}
What I wish is to fetch all "notes" where dueDate has passed.
const now = moment().valueOf() //Eg. 1561629500000
database.ref('notes/')
.orderByChild("dueDate")
.endAt(now)
.once("value", (snapshot) => {
console.log('Process expired notes')
snapshot.forEach( (data) => {
const obj = data.val()
console.log('Date comparison:', (now >= obj.data.alertDate))
...
The code above does not work, it returns all the objects from the example JSON. The console.log logs "False" for three out of four returned objects.
I could do a comparison and only process the objects that meets my criteria, but that would defeat the purpose.
I have indexed the database on ["notes\data\alertDate"].
What am I missing? I must have misinterpreted the documentation somehow. :)
Your dueDate property is nested under data, so you need to address is as data/dueDate:
database.ref('notes')
.orderByChild("data/dueDate")
You might want to include both a startAt() and endAt() clause, with just a reasonable value for startAt() and the specific value you're already using for endAt().
I am trying to grab every project by the members within them -- I've created a sample datastructure though the actual structure is much larger (as in it would be difficult to restructure the database).
Here is my query:
var ref = new Firebase(FBURL + '/chat/meta/project');
var email = 'kerry#email.com';
ref
.orderByChild("email")
.equalTo(email)
.on("child_added", function(snapshot) {
console.log(snapshot.val());
}
);
It is important to note that if I remove the .equalTo(email) that it returns all of the "projects", when it should only return 2 of them.
Here is the data in Firebase:
{
"chat" : {
"meta" : {
"project" : {
"-KAgjWOxjk80HIbNr68M" : {
"name" : "Gman Branding",
"url" : "http://localhost:3000/project/abc123fasd123cc/...",
"date" : "2015-10-10T21:33:25.170Z",
"member" : {
"-KAgkD-2GVESwNwKP3fA" : {
"email" : "abc#gman.com"
},
"-KAgkP3M4nug9Bjn-vY6" : {
"email" : "def#gman.com"
},
"-KAgkP3OF0sUgc9x9p37" : {
"email" : "ghi#gman.com"
},
"-KAgkaMyEOiXft6o-HbO" : {
"email" : "kerry#email.com"
}
}
},
"-KAgl9xlPDU5T4072FgE" : {
"-KAglqH9pxkhgC84_kAl" : {
"name" : "YuDog",
"url" : "http://localhost:3000/project/abc123fasd123cc/...",
"date" : "2015-10-10T21:41:31.172Z"
},
"name" : "billing test 1",
"url" : "http://localhost:3000/project/abc123fasd123cc/...",
"date" : "2015-02-25T23:18:55.626Z",
"dateNotifyUnread" : "2016-01-25T23:23:55.626Z",
"member" : {
"-KAglNsswyk66qUZNrTU" : {
"email" : "kerry#email.com"
}
}
},
"-KAgltmLk2oOYhEDfwRL" : {
"-KAgm1Jt5q53gzLm1GIh" : {
"name" : "YuDog",
"url" : "http://localhost:3000/project/abc123fasd123cc/...",
"date" : "2015-10-10T21:41:31.172Z"
},
"name" : "YuDog",
"url" : "http://localhost:3000/project/abc123fasd123cc/...",
"date" : "2015-10-10T21:41:31.172Z",
"member" : {
"-KAgm1Jvss9AMZa1qDb7" : {
"email" : "joe#yudog.com"
}
}
},
"-KAgluTcE_2dv00XDm1L" : {
"-KAgm6ENmkpDiDG2lqZ4" : {
"name" : "YuDog Landing Page",
"url" : "http://localhost:3000/project/abc123fasd123cc/...",
"date" : "2015-10-10T21:41:31.172Z"
},
"-KAgmBptbeInutRzNinm" : {
"name" : "YuDog Landing Page",
"url" : "http://localhost:3000/project/abc123fasd123cc/...",
"date" : "2015-10-10T21:41:31.172Z"
},
"name" : "YuDog Landing Page",
"url" : "http://localhost:3000/project/abc123fasd123cc/...",
"date" : "2015-10-10T21:41:31.172Z",
"member" : {
"-KAgm6EQcvQg3oP-OnIF" : {
"email" : "joe#yudog.com"
},
"-KAgmBpwoxPYGXS9fLZ9" : {
"email" : "joe#yudog.com"
}
}
}
}
}
}
}
I've looked at 8-10 other links on SO but haven't found any that solve this issue.
The solution is to create a data structure that matches your needs. In this case, you want to look up the projects for a user based on their email address. So we'll add a node that contains this mapping:
"projects_by_email": {
"kerry#email,com": {
"-KAgjWOxjk80HIbNr68M": true,
"-KAgl9xlPDU5T4072FgE": true
},
"abc#gman,com": {
"-KAgjWOxjk80HIbNr68M": true
}
...
}
This is called denormalizing your data, although I often think of them as inverted indexes. I would probably keep the projects by uid, but the structure would be the same.
With a structure like this, you can get the list of projects for an email with a simple direct look up:
var ref = new Firebase(FBURL);
var email = 'kerry#email.com';
ref.child('projects_by_email')
.child(email)
.on("child_added", function(snapshot) {
console.log(snapshot.key());
}
);
Or if you then also want to "join" the projects themselves:
var ref = new Firebase(FBURL);
var email = 'kerry#email.com';
ref.child('projects_by_email')
.child(email)
.on("child_added", function(snapshot) {
ref.child('project').child(snapshot.key()).once('value', function(projectSnapshot) {
console.log(projectSnapshot.val());
});
}
);
This type of denormalizing is a normal part of NoSQL data modeling. The duplication may feel wasteful, but it is part of why NoSQL solution scale so well: none of the code above asks the database to consider all projects/all users. It's all directly accessing the correct nodes, which scales really well. So we're sacrificing storage space to gain improved performance/scalability; a typical space vs time trade-off.
I have the following Mongoose schema and model:
var deviceSchema = new Schema({
deviceId:String,
deviceName:String,
devicePlace:String,
socket : [{number: Number,name:String, state : Boolean, current: Number, image:Number,locked:Boolean,reserved:Boolean}]
});
I already have a device in my database with four sockets.
Here example!
This is original data.
{
"_id" : ObjectId("5626569006bc3da468bafe93"),
"deviceId" : "0013A20040B5769A",
"deviceName" : "device",
"devicePlace" : "place",
"__v" : 0,
"socket" : [
{
"_id" : ObjectId("5628bd83570be84e28879e2d"),
"number" : 0,
"name" : "name"
"state" : true,
"current" : 0
"image" : 0,
"locked" : false,
"reserved" : false,
}, ...
]
}
and I received data from client for update.
{
"_id" : ObjectId("5626569006bc3da468bafe93"),
"deviceId" : "0013A20040B5769A",
"__v" : 0,
"socket" : [
{
"_id" : ObjectId("5628bd83570be84e28879e2d"),
"number" : 0,
"name" : "new name!!!!!"
"state" : true,
"current" : 0
}, ...
]
}
Now I'm trying to update a specific socket's name in the database with the following command:
device.update({deviceId: newData.deviceId, "socket.number": newData.number}, {$set: {"socket.$.name": newData.name}})
newData is object that extracted from socket array in received data.
I want to just update first socket's name.
or if possible, I want to update every socket's name as received socket array.
But this does not seem to be working, but I get no error. Can someone pin point what I'm doing wrong?
Add the callback to the update statement to see the error trace.
device.update({deviceId:newData.deviceId,'socket.number':newData.number}
,{$set: {"socket.$.name" : newData.name}}
,function(error,updatedDevice){
if(error) throw error;
// or : console.log("update error",error.message);
})
Im trying to access some data and keep getting errors no matter what I try. Please help.
"rain":{"3h":13.625} is the part of the JSON file I am trying to access.
Here is what I have tried:
var currentRain = data.rain.3h; Which is most logical as it worked before but the number is what is giving the error.
var currentRain = data.rain["3h"];
var currentRain = data.rain[0]["3h"];
var currentRain = data.rain["3h"][0];
UPDATE:
This is the JSON payload:
{ "base" : "stations",
"clouds" : { "all" : 92 },
"cod" : 200,
"coord" : { "lat" : -33.850000000000001,
"lon" : 151.22
},
"dt" : 1429558616,
"id" : 6619279,
"main" : { "grnd_level" : 1024.97,
"humidity" : 100,
"pressure" : 1024.97,
"sea_level" : 1031.0999999999999,
"temp" : 288.77699999999999,
"temp_max" : 288.77699999999999,
"temp_min" : 288.77699999999999
},
"name" : "City of Sydney",
"rain" : { "3h" : 13.625 },
"sys" : { "country" : "AU",
"message" : 0.0101,
"sunrise" : 1429474880,
"sunset" : 1429514809
},
"weather" : [ { "description" : "heavy intensity rain",
"icon" : "10n",
"id" : 502,
"main" : "Rain"
} ],
"wind" : { "deg" : 157.5,
"speed" : 8.3200000000000003
}
}
You'll need to use ["bracket notation"] to access this, since "3h" begins with a number. As MDN explains:
An object property name can be any valid JavaScript string, or anything that can be converted to a string, including the empty string. However, any property name that is not a valid JavaScript identifier (for example, a property name that has a space or a hyphen, or that starts with a number) can only be accessed using the square bracket notation.
This is the correct JSON:
{
"rain": {
"3h": 13.625
}
}
First you need to parse it and transform into an object:
var jsonToObject = JSON.parse('{"rain":{"3h":13.625}}');
You can now access it like this:
jsonToObject.rain["3h"]
Just use data["rain"]. If you need to parse it first do JSON.parse(data) and then data["rain"].
OUTPUT
console.log(data["rain"]);
> { '3h': 13.625 }
...keep in mind that will return an Object.
This line in my JS file:
RedQueryBuilderFactory.create(config,
'SELECT "x0"."title", "x0"."priority" FROM "ticket" "x0" WHERE ("x0"."status" = (?))',
[]
);
works fine witih an empty array as the 3rd parameter. This parameter is supposed to be an array of strings according to the documentation and any sample code I can find. When I pass a string in the array it fails:
RedQueryBuilderFactory.create(config,
'SELECT "x0"."title", "x0"."priority" FROM "ticket" "x0" WHERE ("x0"."status" = (?))',
['in_process']
);
I get java.lang.ClassCastException in the Safari console. Here's the related part of the config if it's relevant:
var config = {
meta : {
tables : [ {
"name" : "ticket",
"label" : "Ticket",
"columns" : [ {
"name" : "title",
"label" : "Title",
"type" : "STRING",
"size" : 255
}, {
"name" : "priority",
"label" : "Priority",
"type" : "REF"
} ],
fks : []
} ],
types : [ {
"name" : "REF",
"editor" : "SELECT",
"operators" : [ {
"name" : "IN",
"label" : "any of",
"cardinality" : "MULTI"
}]
} ]
}
};
Looks like this is a bug in passing in parameter values. Internally it is expecting a collection but this is not happening.
Best if you raise a https://github.com/salk31/RedQueryBuilder bug report here?
NB Should be "IN" not "="