Iterate over a Js array with two objects (firebase) - javascript

I'm using firebase to make a chat application. I stumbled upon a little problem.
When making requests to the firebase database, firebase will return a JSON or JS object back (I'm new to this so I don't really know).
This is the structure of my database:
The first ID under the message tree is the client's ID which I get when a cidst connects to the application. The id's just below are the client'ID with whom the logged client chatted with and the Id below that is firebase generated ID for each message.
With this code (see below) I'm listening on the database to see if any messages have been added for notification purposes.
var ref = database.ref('messages/81k44hlET5cq2AorxLDxD1DeXV52/');
ref.on('value', gotData, errData);
function gotData(data) {
var msgs = data.val();
var keys = Object.keys(msgs);
console.log(msgs);
messages = new Array();
timestamp = new Array();
type = new Array();
for(var keys in msgs) {
if (msgs.hasOwnProperty(keys)) {
console.log(keys + " -> " + msgs[keys]);
messages.push(msgs[keys]);
}
}
}
The output of the code:
I'm getting an array with two objects. Until here everything works fine.
My problem is that I can't figure out how I can get my message properties from here using JavaScript since the Message-IDs are unknown.
What I mean is that I can't access the properties doing msgs[keys].id.message for example since ID is unknown.

var ref = database.ref('messages/81k44hlET5cq2AorxLDxD1DeXV52/');
ref.on('value', gotData, errData);
function gotData(data)
{
var msgs = data.val();
var keys = Object.keys(msgs);
console.log(msgs);
messages = new Array();
timestamp = new Array();
type = new Array();
for(var keys in msgs)
{
if (msgs.hasOwnProperty(keys)) {
console.log(keys , " -> " , msgs[keys]);
messages.push(msgs[keys]);
var k = msgs[keys];
for(var keys in k){
console.log( k[keys]);
}
//
}
}

You could iterate over your JavaScript object with the .forEach method, use Object.entries for this.
In the following code snippet, I am logging all message objects
const messages = {
kjzn5ef6ke2zlfzn: {
h6qjopdbgs5d6mv7f: {
gd73g4d5d9dvtjzj15: {
message: "k",
seend: "true",
timestamp: "26/6/2018 20",
type: "send"
},
kdaz8bamd6kprmq78: {
message: "k",
seend: "true",
timestamp: "26/6/2018 20",
type: "send"
}
}
}
};
Object.entries(messages).forEach(([id1, a]) => {
Object.entries(a).forEach(([id11, b]) => {
Object.entries(b).forEach(([id111, message]) => {
console.log(id1, '=>', id11, '=>', id111, ':', message)
});
});
});

Related

Updating multiple objects in an Array belonging to a collection

I'm using MERN stack for my program with mongoose for accessing the database. I have a collection called Movies and I wanted to edit multiple objects in an array within this collection. This is what the Movie Schema contains in my database:
I wanted to edit multiple objects in the 2D array within seats and to change isReserved to True.
I just used findOne in accessing the data since I still don't know how to update the objects that I want to access.
app.post('/confirm/:movieId/:timeId', (req, res) => {
const movieId = req.params.movieId;
const timeId = req.params.timeId;
const selectedSeats = req.body;
// console.log("in confirm DB ");
// console.log(selectedSeats);
let getSeats;
let getTimeSlots;
const length_timeId = timeId.length;
Movies.findOne({ movieId }, (err, movie) => {
console.log("INSIDE");
getTimeSlots = movie['timeslots'];
let index = timeId.substring(1, length_timeId);
//get the seats
getSeats = getTimeSlots[parseInt(index)-1];
//loop through seats
console.log("PRINTING GET SEATS");
console.log(getSeats);
for(var i=0; i<selectedSeats.length; i++) {
let row = parseInt(selectedSeats[i] / 5);
let id = selectedSeats[i] % 5;
console.log(getSeats["seats"][row][id]);
}
})
})
I already accessed the objects that I want to edit as that code displays this on my terminal:
Would really appreciate some tips on how to update the isReserved status. Thanks!
Do you specify the timeslot and seat by an id or by the index within the array? If you use the index then solution is quite simple
const key = "timeslots." + req.params.timeId + ".seats." + req.body + ".isReserved";
var upd = {};
upd[key] = true;
db.Movies.updateOne({ movieId: req.params.movieId }, { $set: upd })
If your code uses the id then you have to work with array filters, see Update Nested Arrays in Conjunction with $[], so similar to this
db.Movies.updateOne(
{ movieId: req.params.movieId },
{ $set: { "timeslots.$[slot].seats.$[seat].isReserved": true } },
{ arrayFilters: [ { "slot.id": req.params.timeId } , { "seat.id": req.body } ] }
)

How to return an array of children from firebase in React-Native

My Firebase data base contains JSON objects, each with the same parameters as seen below. Firebase data
I want to get an array that has each objects country. So if I have 4,000 objects I want to get an array of 4,000 strings all containing a country.
Right now I can get the console to log all the 4,000 objects into an array using the code below.
componentWillMount() {
this.fetchData();
}
fetchData = async () => {
var data1 = [];
var fireBaseResponse = firebase.database().ref();
fireBaseResponse.once('value').then(snapshot => {
snapshot.forEach(item => {
var temp = item.val();
data1.push(temp);
return false;
});
console.log(data1);
});
}
But when I try doing
var fireBaseResponse = firebase.database().ref().child('country');
I get an array of nothing.
Any help would be great.
As mentioned in the comments, you can create a new temp object containing just country before pushing it into your array.
snapshot.forEach(item => {
var temp = { country: item.val().country };
data1.push(temp);
return false;
});

How to take the last value in certain property from JSON in Angularjs

I have this code in my app.js for send chat and read chat in my application
$scope.messageshistory = {};
$scope.tmp = {};
// send message
$scope.sendMessage = function(){
$scope.messages = {
from : $scope.datauser['data']['_id'],
fromname : $scope.datauser['data']['nama'],
to : $scope.tmpuserid,
message : $scope.tmp['sendmessage'],
time : moment()
};
//event emit message
socket.emit('message',$scope.messages,function(callback){
if(!callback['error']){
$scope.messages['time'] = moment($scope.messages['time']).format('DD-MMMM-YYYY HH:MM');
if ($scope.messageshistory.hasOwnProperty($scope.tmpuserid)){ //yg di json yg paling awal
$scope.messageshistory[$scope.tmpuserid].push($scope.messages);
}else{
$scope.messageshistory[$scope.tmpuserid] = [];
$scope.messageshistory[$scope.tmpuserid].push($scope.messages);
}
$scope.tmp['sendmessage'] = '';
}else{
var msg = callback['error'];
navigator.notification.alert(msg,'','Error Report', 'Ok');
}
$scope.$apply();
});
};
//event read message
socket.on('message', function (data) {
window.plugin.notification.local.add({
id : moment(),
title : data['fromname'],
message : data['message'].substr(0,20) + ' ...',
led : 'A0FF05',
json : JSON.stringify({ routes:'chat', nama :data['fromname'],from:data['from'] })
});
data['time'] = moment(data['time']).format('DD-MMMM-YYYY HH:MM');
if ($scope.messageshistory.hasOwnProperty(data['from'])){
$scope.messageshistory[data['from']].push(data);
}else{
$scope.messageshistory[data['from']] = [];
$scope.messageshistory[data['from']].push(data);
}
for(var i = 0; i<= $scope.datauser['data']['friends'].length; i++){
if($scope.datauser['data']['friends'][i]['userid'] == data['from']){
$scope.datauser['data']['friends'][i]['ischat'] = true;
break;
}
};
$scope.$apply();
});
my question is how to take the last value in message property from $scope.messageshistory, because $scope.messages is for sending the message and $scope.messageshistory is to keep the chat history. This is the chat activity image:
just from this activity, $scope.messageshistory will save the data in it JSON as:
{
"5512": [{
"from": "561c",
"fromname": "ryan",
"to": "5512",
"message": "hey",
"time": "18-Maret-2016 21:03"
}, {
"from": "5512",
"fromname": "sasa",
"to": "561c",
"message": "hello",
"time": "18-Maret-2016 21:03",
"_id": "593s"
}]
}
I get this value from using angular.toJson($scope.messageshistory), and this array will always add up if the chat activities still going on. And my intention to get the last value in message property from $scope.messageshistoryis to use in Text-to-Speech feature in my application. This is the code:
$scope.speakText = function() {
TTS.speak({
text: **this the place for the code**,
locale: 'en-GB',
rate: 0.75
}, function () {
// handle the success case
}, function (reason) {
// Handle the error case
});
};
it will read the last message in $scope.messageshistory. So, what code that I must write to take the last value?
You have to do the following:
var msgs = $scope.messageshistory[$scope.tmpuserid]
var yourLastMessage = msgs[msgs.length-1].message
// you could also add a quick check so you don't get
// an error if the messages array is emtpy :
// var yourLastMessage = (msgs && msgs[msgs.length-1] ? msgs[msgs.length-1].message : null)
Edit
Some explanation per your comment :
var msgs = $scope.messageshistory[$scope.tmpuserid]
// msgs is now an Array containing Objects
// [{message : 'xxx'},{message : 'yyy'}]
// we take the last entry of the msgs Array (msgs.length-1)
// so msgs[msgs.length-1] is the last object ({message : 'yyy'})
// and finally we take the 'message' property' of that object:
var yourLastMessage = msgs[msgs.length-1].message
assuming that the keys in the history object are ascending numbers and taking into account that the order of keys in an object is not specified by W3C you will have to do the following:
get all keys
find the "latest" (hence the biggest number)
fetch it
so you could do for example
var keys = Object.keys($scope.messagehistory);
keys.sort (function (a, b) {
return a - b;
});
var result = keys[keys.length - 1];

Node/Feathers with a database in the back

I am learning about Node and Feathers on a job. Need to make a simple app that would use feathers to load the [nedb] with sample data.
var fake = require('./fake.js');
var feathers = require('feathers-client');
var io = require('socket.io-client');
var socket = io("http://127.0.0.1:8000");
var app = feathers()
.configure(feathers.socketio(socket));
var accountsAPIService = app.service('/api/accounts');
var dummyData = fake();
// import dummy data
for ( var i = 0; i < dummyData.accounts.length; i++) {
// console.log(dummyData.accounts[i]);
var params = { query: {}};
accountsAPIService.create(dummyData.accounts[i], params).then(function(account) {
console.log("inserted: ", account);
});
}
// read back inserted records
accountsAPIService.find(params, function(accounts) {
console.log("accounts: ", accounts);
});
i just need to insert items from the array dummyData.accounts into the server.
When I run the script, it seems that nothing is being imported.
When I read the records back, it returns:
accounts: null
What is the proper way of inserting/creating records with Feathers?
Could not figure out how to use ".then" so used a regular form:
for ( var i = 0; i < dummyData.accounts.length; i++) {
var params = { query: {}};
accountsAPIService.create(dummyData.accounts[i], params, function(error, account) {
// console.log("inserted: ", account);
});
}
That works fine.
To read the data back, I corrected the method signature. Then, it works. :)
accountsAPIService.find(function(error, accounts) {
console.log("accounts: ", accounts);
});

javascript - get items with query and match items to a user who has favorited item

I am writing a script on parse.com's javascript cloud code SDK. Here is the information I have saved in my parse.com account and what I am trying to do with it.
I have a bunch of items saved in a parse class called TestItem, theses items have an objectId, item name, meal time (lunch, dinner) and a location for there columns. I also have a class called UserFavourites. In this class the objects have an objectId, item name and a pointer to the user who saved the item as a favourite.
And with this information I am trying to write a cloud code script in javascript. That will match the an item(s) to the item(s) that a user has favourited and send them a push notification saying where and what the item is and the location of the item. I have some code that will do that but this code will send a different notification for each item which could get annoying for the user here is that code.
Parse.Cloud.define("push", function(request, response) {
var TestItem = Parse.Object.extend("TestItem");
var query = new Parse.Query(TestItem);
query.limit(1000);
query.equalTo('school', 'Union College (NY)');
query.find({
success: function(resultsItem) {
//console.log("Successfully retrieved " + resultsItem.length + " :1111.");
for (var i = 0; i < resultsItem.length; i++) {
var object = resultsItem[i];
var item = object.get('item');
var school = object.get('school');
var meal = object.get('meal');
var meal = meal.toLowerCase();
var diningLocation = object.get('schoolMenu');
//var itemArray = [];
var UserFavourite = Parse.Object.extend("UserFavourite");
var queryFavourite = new Parse.Query(UserFavourite);
queryFavourite.limit(1000);
queryFavourite.equalTo("item", item)
queryFavourite.equalTo("school", school)
queryFavourite.find({
success: function(results) {
for (var i = 0; i < results.length; i++) {
var objectFav = results[i];
var user = objectFav.get('user');
var userID = user.id;
var realItem = objectFav.get('item');
console.log(objectFav.get('user'));
console.log(objectFav.get('item'));
var UserClass = Parse.Object.extend("User");
var queryUser = new Parse.Query(UserClass);
queryUser.get(userID, {
success: function(userResult) {
console.log(userResult.get('school'));
console.log('install:' + userResult.get('installation').id);
var userInstallationId = userResult.get('installation').id;
var queryInstallation = new Parse.Query(Parse.Installation);
queryInstallation.equalTo('objectId', userInstallationId);
queryInstallation.find({
success: function(results) {
console.log('number' + results.length);
Parse.Push.send({
// deviceType: [ "ios" ],
where: queryInstallation,
data: {
alert: realItem + " is being served at " + diningLocation + " for " + meal
}
},
{
success: function() {
// Push was successful
},
error: function(error) {
// Handle error
}
});
},
error: function(error) {
console.log('error');
}
});
},
error: function(error) {
console.log('error');
}
});
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
});
As you can see it is quite long and not very nice looking, I tried to save items to an array so to avoid sending two or more notifications but couldn't get that to work.
So I started writing another script that uses promises which looks much nicer but haven't gotten it all the way right now, it can match the items to users that have an item favourited and put the objectId's of those users in an array. Here is that code.
Parse.Cloud.define("test", function(request, response) {
var UserFavourite = Parse.Object.extend("UserFavourite");
var queryFavourite = new Parse.Query(UserFavourite);
var userArray = [];
var TestItem = Parse.Object.extend("TestItem");
var query = new Parse.Query(TestItem);
query.limit(1000);
query.equalTo('school', 'Union College (NY)');
query.find().then(function(results) {
return results;
}).then(function(results) {
var promises = [];
for (var i = 0; i < results.length; i++) {
var object = results[i];
var item = object.get('item');
var school = object.get('school');
var meal = object.get('meal');
var UserFavourite = Parse.Object.extend("UserFavourite");
var queryUser = new Parse.Query(UserFavourite);
queryUser.equalTo("item", item);
queryUser.equalTo("school", school);
var prom = queryUser.find().then(function(users) {
for (var i = 0; i < users.length; i++) {
var user = users[i];
var userID = user.get('user').id;
if (userArray.indexOf(userID) === -1) {
userArray.push(userID);
}
}
return userArray;
});
promises.push(prom);
}
return Parse.Promise.when.apply(Parse.Promise, promises);
}).then(function(results) {
console.log(userArray);
});
});
But now with this code I don't know where to go, I think using promises and such is the right way to go but I am now confused as once I have all the users that have an item favourited what to do, I then need to get there items that are favourited and are available in the TestItem class, this is where I am struggling.
Here is a pic of my UserFavourite class it has a pointer to the user who favorited the item as you can see, and also a user has more than one favorite.
Thanks a bunch for the help in advance.
Here is your code, and I changed a couple things.
Parse.Cloud.define("getAllFavoriteItems", function (request, response) {
var TestItems = Parse.Object.extend("TestItems");
var UserFavorites = Parse.Object.extend("UserFavorites");
var testItemsQuery = new Parse.Query(TestItems);
var userFavoritesQuery = new Parse.Query(UserFavorites);
testItemsQuery.equalTo('school', 'Union College (NY)');
userFavoritesQuery.include('testItems'); //This makes sure to pull all of the favorite item data instead of just the pointer object
userFavoritesQuery.matchesQuery('testItem', testItemsQuery); //This will run this second query against the TestItems
userFavoritesQuery.limit(1000); //limit results to 1000
userFavoritesQuery.ascending('userId'); //group the user id's together in your array
userFavoritesQuery.find({
success:function(results) {
var pushNotificationMessage = "";
var userId = "";
for (var i=0; i <results.length; i++) {
if (results[i].get('userId') != userId) {
if (results[i].get('userId') != "") {
//TODO send push notification
}
userId = results[i].get('userId');
pushNotificationMessage = ""; //start a new push notification
}
pushNotificationMessage += results[i].get('item').get('name') + ": " + results[i].get('item').get('location') + "\n";
//SOMEWHERE BEFORE HERE I NEED THE INSTALLATION ID OF THE USER
//TO SEND THE PUSH TO THAT USER
Parse.Push.send({
// deviceType: [ "ios" ],
where: queryInstallation,
data: {
alert: pushNotificationMessage
}
},
{
success: function() {
// Push was successful
},
error: function(error) {
// Handle error
}
});
}
response.success(true);
},
error:function(error) {
response.error();
}
})
});
Some code that might create push per user, rough outline though
if (i > 0) {
if (results[i].get('user') === results[i-1].get('user')) {
userItems.push(results[i]);
}
else {
userItems.length = 0;
}
}
else {
userItems.push(results[i]);
}
Not sure let me know if you understand what I'm trying to do...
So it a user has two items favourited I want it to group that into one, phrase that says what and where both items are being served
And here is code to send push
Parse.Push.send({
// deviceType: [ "ios" ],
where: queryInstallation,
data: {
alert: pushNotificationMessage
}
},
{
success: function() {
// Push was successful
},
error: function(error) {
// Handle error
}
});
It can also be done with then/ promises,
I agree with #Maxwell that your UserFavorite should have links to both User and TestItem. This makes it possible to make your cloud-function as simple as:
Parse.Cloud.define("getAllFavoriteItems", function(request, response) {
var TestItem = Parse.Object.extend("TestItem");
var UserFavorites = Parse.Object.extend("UserFavorites");
var testItemsQuery = new Parse.Query(TestItem);
var userFavoritesQuery = new Parse.Query(UserFavorites);
testItemsQuery.equalTo('school', request.params.school);
userFavoritesQuery.include('testItem');
userFavoritesQuery.include('user');
userFavoritesQuery.matchesQuery('testItem', testItemsQuery); //This will run this second query against the TestItems
userFavoritesQuery.find().then(function(results) {
var alerts = {};
for(var i =0 ; i<results.length; i++ ){
var user = results[i].get('user');
var testItem = results[i].get('testItem');
if(user && testItem){
var instId = user.get('installationId');
if(!alerts[instId]) {
alerts[instId] = [];
}
var m = results[i].get('item') + " is being served at {{diningLocation}} for " + testItem.get('meal');
alerts[instId].push(m);
}
}
response.success(alerts);
}, function(error) {
response.error();
});
});
This is working code that you can also find in my github repo.
You can also see the working demo here
The idea is the same as in Maxwell's answer: to have link in UserFavorites class to both User (where installationId is located) and TestItem entities. I've just made it working by including user and testItems properties in query, so when the result is returned filtered by school name I already have a list of installationIds.
Here is my schema:
User
TestItem
UserFavorites
Update:
In this code I added push notifications:
Parse.Cloud.define("getAllFavoriteItems", function(request, response) {
var TestItem = Parse.Object.extend("TestItem");
var UserFavorites = Parse.Object.extend("UserFavorites");
var testItemsQuery = new Parse.Query(TestItem);
var userFavoritesQuery = new Parse.Query(UserFavorites);
testItemsQuery.equalTo('school', request.params.school);
function SendPush(installationId, msg) {
var query = new Parse.Query(Parse.Installation);
query.equalTo('objectId', installationId);
Parse.Push.send({
where: query,
data: {alert: msg}
});
}
userFavoritesQuery.include('testItem');
userFavoritesQuery.include('user');
userFavoritesQuery.matchesQuery('testItem', testItemsQuery); //This will run this second query against the TestItems
userFavoritesQuery.find().then(function(results) {
var groupedAlerts = {};
// manually iterating though results to get alert strings ang group by user in groupedAlerts[installationId]
for(var i =0 ; i<results.length; i++ ){
var user = results[i].get('user');
var testItem = results[i].get('testItem');
if(user && testItem){
var instId = user.get('installationId');
if(!groupedAlerts[instId]) {
groupedAlerts[instId] = [];
}
var m = results[i].get('item') + " is being served at {{dining Location}} for " + testItem.get('meal');
groupedAlerts[instId].push(m);
}
}
// reformat to array and send push notifications
var alerts = [];
for(var key in groupedAlerts) {
alerts.push({
installationId: key,
alerts: groupedAlerts[key],
});
// Send push notifications
SendPush(key, groupedAlerts[key].join());
}
response.success(alerts);
}, function(error) {
response.error();
});
});
I've also updated test data in live demo (just press Get Alerts) or feel free to play around with test data hot it changes cloud code response. gitnub repo is also up to up to date.
This is based on what I understand as the problem you're trying to solve. If it's not addressing the right issue, let me know and I'll see what I can do.
Looking first at your database model, we can simplify this a bit by modifying the UserFavorites table. Starting with the initial two classes, you have a table of items and a table of users. Since a user can favorite many items and an item can be favorited by many users, we have a many-to-many relationship that exists. When this happens, we need to make a third class that points to each of the other two classes. This is where the UserFavorites table comes into play. In Parse terms, the UserFavorites table needs to have two pointers in it: one for the user and one for the item.
Once the UserFavorite table exists with it's two pointers, we can do a few things fairly easily. In your case, we have a few searching criteria:
each item must be at a given school
you want to limit your responses to the first 1000
To accomplish this you can combine two queries into one by calling matchesQuery.
Parse.Cloud.define("getAllFavoriteItems", function (request, response) {
var TestItems = Parse.Object.extend("TestItems");
var UserFavorites = Parse.Object.extend("UserFavorites");
var testItemsQuery = new Parse.Query(TestItems);
var userQuery = new Parse.Query(Parse.User);
var userFavoritesQuery = new Parse.Query(UserFavorites);
testItemsQuery.equalTo('school', 'Union College (NY)');
userQuery.include('Installation');
userFavoritesQuery.include('testItems'); //This makes sure to pull all of the favorite item data instead of just the pointer object
userFavoritesQuery.include('User'); //This makes sure to pull all of the favorite item data instead of just the pointer object
userFavoritesQuery.matchesQuery('testItem', testItemsQuery); //This will run this second query against the TestItems
userFavoritesQuery.matchesQuery('user', userQuery); //This will run the third query against Users, bringing the installation data along with it
userFavoritesQuery.limit(1000); //limit results to 1000
userFavoritesQuery.ascending('userId'); //group the user id's together in your array
userFavoritesQuery.find({
success:function(results) {
...
},
error:function(error) {
response.error();
}
})
})
Once we get that far, then compiling the push message for each user should be a matter of straight-forward string parsing logic. For example, in the success function, one way we can extract the data we is this:
success:function(results) {
var pushNotificationMessage = "";
var userId = "";
for (var i=0; i <results.length; i++) {
if (results[i].get('userId') != userId) {
if (results[i].get('userId') != "") {
//TODO send push notification
}
userId = results[i].get('userId');
pushNotificationMessage = ""; //start a new push notification
}
pushNotificationMessage += results[i].get('item').get('name') + ": " + results[i].get('item').get('location') + "\n";
}
response.success(true);
}
I haven't tested these examples to see if they'll work, but I hope this gives you an idea of how to simplify your queries into something a little more manageable.

Categories