Using promises in Geofire - javascript

The Geofire documentation says that Geofire returns promises when reading and writing data but I cannot seem to find any examples of this. I was wondering how I could use this in javascript to attach a function onto the end of the listener that fired when the geofire promise is fulfilled. My code is:
var onKeyEnteredRegistration = this.geoQuery.on("key_entered", function(key, location, distance) {
console.log(key + " entered query at " + location + " (" + distance + " km from center)");
}).then(function(result){
console.log("promise resolved with:" + result);
}, function(error){
console.error(error)
});
But this is outputting an error saying 'undefined is not a function' referencing the chained function. Does anyone know how to use promises in Geofire?
Thanks

So only the get, set and remove functions on the GeoFire class return promises. Like so:
geoFire.get("some_key").then(function(location) {
if (location === null) {
console.log("Provided key is not in GeoFire");
}
else {
console.log("Provided key has a location of " + location);
}
}, function(error) {
console.log("Error: " + error);
});
However the on function instead returns a GeoQuery whose on function returns a GeoCallbackRegistration which is used to kill the query with the cancel function (which does not return anything.)
var onKeyEnteredRegistration = this.geoQuery.on("key_entered", function(key, location, distance) {
console.log(key + " entered query at " + location + " (" + distance + " km from center)");
});
onKeyEnteredRegistration.cancel(); // the "key_entered" event will stop firing

Related

How to get all columns from a Parse platform class

I am trying to get all columns from a class in a Parse platform using cloud code that returns a list/array of all the names of the columns.
I am looking at the schema section of the documentation, but I can't find how to get the column's names, only adding, deleting, ...
However, I found this method, but I haven't figured out how to use it neither found any example.
This is what I have right now (doesn't work, neither is the only thing I tried, but hopefully it can help you understand my situation):
Parse.Cloud.define("getAllProperties", async (request) => {
var mySchema;
try {
mySchema = new Parse.Schema('Entry');
} catch (error) {
console.error("ERROR " + error.code + ': ' + error.message);
return error;
}
console.log("CloudFunction 'getAllProperties' executed successfully.");
return mySchema.toString();
});
I found a way to do it:
Parse.Cloud.define("getAllProperties", async (request) => {
var mySchema;
try {
mySchema = new Parse.Schema('Entry');
mySchema = await mySchema.get()
} catch (error) {
console.error("ERROR " + error.code + ': ' + error.message);
return error;
}
console.log("CloudFunction 'getAllProperties' executed successfully.");
return JSON.stringify(mySchema);
});

Firebase cloud functions: "Unhandled error RangeError: Maximum call stack size exceeded"

I have a cloud function that uses firebase and after I call it from my angular app I get the mentioned above error:
Unhandled error RangeError: Maximum call stack size exceeded
at baseKeys (/workspace/node_modules/lodash/lodash.js:3483:12)
at keys (/workspace/node_modules/lodash/lodash.js:13333:60)
at /workspace/node_modules/lodash/lodash.js:4920:21
at baseForOwn (/workspace/node_modules/lodash/lodash.js:2990:24)
at Function.mapValues (/workspace/node_modules/lodash/lodash.js:13426:7)
at encode (/workspace/node_modules/firebase-functions/lib/providers/https.js:184:18)
at /workspace/node_modules/lodash/lodash.js:13427:38
at /workspace/node_modules/lodash/lodash.js:4925:15
at baseForOwn (/workspace/node_modules/lodash/lodash.js:2990:24)
at Function.mapValues (/workspace/node_modules/lodash/lodash.js:13426:7
I've searched stack to find solutions - but in most cases there was serialization problem, that I believe DOES NOT happen here.
Here is my function:
exports.createCase = functions.region('europe-west2').https.onCall((data, context) => {
console.log("creating new case");
if (!context.auth) {
throw new functions.https.HttpsError('failed-precondition', 'This function must be called ' +
'while authenticated.');
}
const caseName = data.caseName;
// Authentication / user information is automatically added to the request.
const uid = context.auth.uid;
const name = context.auth.token.name || null;
const picture = context.auth.token.picture || null;
const email = context.auth.token.email || null;
console.log("caseName=" + caseName + " uid=" + uid + " name=" + name + " picture=" +
picture + " email=" + email);
var operationResult = new Promise ((resolve, reject) => {
var accessData : any = {};
var accessId = admin.database().ref('/access/').push();
var operationId = admin.database().ref('/operationslog/' + accessId.key + '/').push();
console.log("accessId created=" + accessId + ' || ' + accessId.key + ' operations id=' +
operationId + ' || ' + operationId.key);
let now: number = Date.now();
accessData[`/access/` + accessId.key] = new Access(caseName, uid, email);
accessData[`/operationslog/` + accessId.key + `/` + operationId.key] = {
date: now,
performedByUser: uid,
performedByMail: email,
performedByImg: picture,
performedBySystem: false,
operationType: 'CREATE',
order: (REVERSE_ORDER_MAX - now),
details: {creator: uid, name: caseName}
};
console.log('commiting data');
admin.database().ref().update(accessData).then( (value: void) => {
console.log("returning ok result");
resolve({
status: "Ok",
accessId: accessId,
description: 'Case created'
});
}, err => {
console.log("Error while trying to create case: " + err);
reject("CASE NOT CREATED");
}
).catch(exception => {
console.log("Error while trying to create case: " + exception);
reject("CASE NOT CREATED");
}
);
}
);
return operationResult;
});
and the call from Angular app:
let createCaseCall = functions.httpsCallable('createCase');
createCaseCall({caseName: value.caseName}).then(result => {
// Read result of the Cloud Function.
console.log("got result: " + result);
if (result.data.status == 'Ok') {
this.showSuccessMessage('Case created.');
}
}).catch(err => {
console.log("Error while calling cloud functions: " + err);
this.showErrorMessage('Error while creating the case.');
});
Now, the important information is that, the data in firebase realtime database IS CREATED when this function is called and console log does contain "returning ok result" line...
It is still a serialization problem.
Here's what you're trying to send back to the client:
resolve({
status: "Ok",
accessId: accessId,
description: 'Case created'
});
accessId is the result of a push operation:
var accessId = admin.database().ref('/access/').push();
That means it's a DatabaseReference object, which contains circular references that can't be serialized. It's not a simple data type, like a string.
You'll want to think more carefully about what you want exactly you want to send back to the client app. Maybe you wanted to send back the name or path of the child key that was created by push()?
Also, you'll probably want to remove the whole new Promise() thing, as that's an anti-pattern here. There is no need to create a new promise when you have promises from all the other database operations available to work with.

Parse dot com destroy all userdata from parse database

I want to set up my custom code in cloud code of parse.
Parse.Cloud.job("deleteUser", function(request, status) {
const query = new Parse.Query("SegmentData");
query.equalTo("userID", request.userID);
query.find()
.then(Parse.Object.destroyAll)
.catch(function(error) {
console.error("Error finding related comments " + error.code + ": " + error.message);
});
const query2 = new Parse.Query("ShowData");
query.equalTo("userID", request.userID);
query.find()
.then(Parse.Object.destroyAll)
.catch(function(error) {
console.error("Error finding related comments " + error.code + ": " + error.message);
});
});
This is the code I have written so far. I want to destroy all the users that have username. They can be even more than 1000. Will this work if the users have more than 1000 records or do I have to amend my code?
With the parse-server the limit of each query is 100 you need to set to
query.limit(1000);
If you want to have 1000 users maximum
You can see here how parse-server test and set the limit of each query:
https://github.com/parse-community/parse-server/blob/master/spec/ParseAPI.spec.js#L314
https://github.com/parse-community/parse-server/blob/master/src/Routers/ClassesRouter.js#L29

How to get count of relation field in parse

GameScore object have one Relation field named Badges.
How I can get count of all objects in this relation in query:
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerName", "Dan Stemkoski");
query.find({
success: function(results) {
alert("Successfully retrieved " + results.length + " scores.");
// Do something with the returned Parse.Object values
for (var i = 0; i < results.length; i++) {
var object = results[i];
alert(object.id + ' - ' + object.get('playerName'));
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
I need something like:
object.Badges.count
or
object.Badges.length
A Parse.Relation object is actually a query description that will return the objects in that relation, so for this case you'd need to run another query for each GameScore:
query.find().then(function (gameScores) {
alert("Successfully retrieved " + gameScores.length + " scores.");
var countPromises = gameScores.map(function (gs) {
// the following executes a count() query, which is severely penalized by Parse
return gs.get('Badges').query().count()
.then(function (count) {
// this extra step is to add the retrieved count as an extra property to the GameSccore object,
// instead of returning only the counts
gs.count = count;
return gs;
});
});
return Parse.Promise.when(countPromises);
}).then(function () {
var gameScoresWithBadgeCount = Array.prototype.slice.call(arguments);
}).fail(function(error) {
alert("Error: " + error.code + " " + error.message);
});
This causes a lot of extra round trips (I assume you're on a browser environment because of alert()), and calls count() queries which are additionally limited by Parse.
What I can recommend you is to keep a count cache as an extra field on the GameScore class, and update it accordingly through CloudCode hooks. Alternatively, you can try to avoid the Relation and make the equivalent using an Array field if possible, through which you can always include the related Badges if needed or get their count without querying for them at all!
Sadly, tougher than one would hope. It requires another asynch trip through the data, so your callback form can do it, but isn't really up to the job. Here it is with promises...
// return a promise that's fulfilled with a badges count for the passed GameScore
function badgeCountOfGameScore(gameScore) {
var relation = gameScore.get("Badges"); // it must have a relation col called Badges for this to work
return relation.query.find().then(function(results) {
return results.length;
});
}
Now your original function redone with promises (and underscore to better handle arrays)...
var _ = require("underscore");
function bunchOfBadgeCounts() {
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerName", "Dan Stemkoski");
return query.find().then(function(results) {
alert("Successfully retrieved " + results.length + " scores.");
var promises = _.map(results, function(object) {
return badgeCountOfGameScore(object);
});
return Parse.Promise.when(promises);
}).then(function() {
alert("Counts = " + JSON.stringify(_.toArray(arguments)));
}, function (error) {
alert("Error = " + JSON.stringify(error));
});
}

Destroying objects from Parse Cloud is unreliable

I'm trying to delete all objects in a class, but whenever I attempt to delete objects from a cloud function or job I get an inconsistent number of objects left over. The jobs always take under second, so I don't think that's the issue (working with under 100 objects anyway). I seem to always have a random number of objects left over and no errors. This is what I'm working with now.
Parse.Cloud.job("deletePosts", function(request, status) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query("Posts");
query.find({
success: function(results) {
Parse.Object.destroyAll(results).then(function() {
console.log("Delete job completed.");
status.success("Delete job completed.");
});
},
error: function(error) {
console.log("Error in delete query error: " + error);
status.error("Error in delete query error: " + error);
}
});
});
When deleting objects in cloud code, use query.each instead of query.find to ensure that you delete all objects matching the query .
find has the query limitation of 100 objects returned by default (or up to 1000 if limit is used). Source
Below is an example of using a promise chain which calls destroy on each Post object. When all of the destroy promises have completed, the success status will be reached, and if any of the destroys fail then the error status will be reached.
Parse.Cloud.job("deletePosts", function(request, status) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query("Posts");
query.each(function(post) {
return post.destroy();
}).then(function() {
console.log("Delete job completed.");
status.success("Delete job completed.");
}, function(error) {
alert("Error: " + error.code + " " + error.message);
status.error("Error: " + error.code + " " + error.message);
});
});

Categories

Resources