Using afterDelete trigger to modify a lot of users - parse-platform

When a specific object is deleted, I need to use an afterDelete trigger to remove references to the object that was just deleted. Specifically, the User class has a column that is a pointer to an object of the type that was just deleted. Therefore I need to unset that column for users who had that set to the object that was just deleted. To do this I am querying for the users, looping over the results of the query, unseting the attribute, then calling saveAll. My worry is that the results of the query may return a lot of users, and I need to ensure all of them are updated.
My question is, do Cloud Code triggers have the 1000 max query limit? Is there a better way to unset this pointer once that object is deleted? Is there no automatic removal of pointers to this deleted object?
Parse.Cloud.afterDelete("Book", function(request) {
Parse.Cloud.useMasterKey();
var book = request.object;
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("Favorite_Book", book);
userQuery.limit(1000);
userQuery.find( {
success:function(users){
for (var i = 0; i < users.length; i++) {
users[i].unset("Favorite_Book");
}
Parse.Object.saveAll(users, {
success: function(users) {},
error: function(users, error) {
console.error("Failed to update users: " + error.code + ": " + error.message);
}
});
}, error: function(error) {
console.error("Failed to fetch users: " + error.code + ": " + error.message);
}
});
});

There are mainly two issue you need to know:
Parse query returns only maximum of 1000 records. To process more records, you need paginate the results using skip method on your query object. You can use Promises in Series to process all your records in batches of 1000 records.
On Parse free plan, you are limited to make only 1800 requests per minute. This means that you cannot save/update a large number of records over a short time span.

Related

Why Parse server is creating new object instead of updating?

I am running parse server in NodeJS environment with express.
Generally, Parse automatically figures out which data has changed so only “dirty” fields will be sent to the Parse Cloud. So, I don’t need to worry about squashing data that I didn’t intend to update.
But why this following code is saving new data every time instead of updating the existing document data with name "Some Name".
// Parse code
Parse.initialize(keys.parseAppID);
Parse.serverURL = keys.parseServerURL;
var GameScore = Parse.Object.extend("GameScore");
var gameScore = new GameScore();
let data = {
playerName: "Some Name",
score: 2918,
cheatMode: true
};
gameScore.save(data, {
success: (gameScore) => {
// let q = new Parse.Query("GameScore");
// q.get(gameScore.id)
console.log("ID: " + gameScore.id)
},
error: function (gameScore, error) {
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and message.
alert('Failed to create new object, with error code: ' + error.message);
}
});
// End of Parse code
The problem is that you're executing the query to find which object you want to update, but then you're not using the results when you go to save data.
query.first({ // This will result in just one object returned
success: (result) => {
// Check to make sure a result exists
if (result) {
result.save(data, {
// Rest of code
Note: You're treating playerName as a unique key. If multiple users can have the same playerName attribute, then there will be bugs. You can use id instead which is guaranteed to be unique. If you use id instead, you can utilize Parse.Query.get
Edit:
Since you want to update an existing object, you must specify its id.
var GameScore = Parse.Object.extend("GameScore");
var gameScore = new GameScore();
gameScore.id = "ID"; // This id should be the id of the object you want to update

Query based on Pointer Values

I have read majority of the questions which quite havent helped me.
So I have three tables, User (parse Default), DataSet and Datapoint.
DataSet is linked to User based on Pointer.
Datapoint is linked to Dataset based on Pointer (object ID of DataSet).
I can easily load DataSets for each User Parse. What i would like to do is load datapoints for a dataset.
I am using Angular, and I can pass the dataset object to, and based of that ID I want to be able to get datapoints for that dataset.
He is what I have so far.
getmyDataPoint: function getMyDataPoint(dataset, callback) {
//get object ID of dataset
var datasetid = dataset.id;
var query = new Parse.Query(Datapoint);
query.include('inDataset');
//inDataset is column name that is pointer, linking to dataset.
query.EqualTo('inDataset', datasetid);
query.find({
success: function(results) {
callback(results);
alert("found some here " + results);
},
error: function(error) {
alert("Error: no datapoint found " + error.message);
}
});
As you would know this quite doesnt work. Any help?
Lets assume you fix up your classes as follows:
DataSet class
user: Pointer<User>
Datapoint class
inDataset: Pointer<DataSet>
Now you can query for Datapoint rows where the inDataset column matches a DataSet quite easily:
query.equalTo('inDataset', dataset);
Under the covers Parse's SDK extracts the object ID and matches on that, but using an actual pointer makes other types of queries possible that you couldn't do with just the strings as you are currently doing it.

Parse Query with array include not always returning every array object

I'm running into some strange behavior when using Parse.Query.find() and am hoping someone can show me my errors. My scenario is that I'm including an array field in my query and sometimes, at a random record, some of the included array elements are null. I've verified that the array elements are indeed NOT null. Additionally, if I use each() instead of find(), I don't see this problem. Also, if I reduce the # of records I read at a time (CHUNK_SIZE) from Parse's 1000 maximum to 500, things work, so I'm not sure what's going on.
Here's the code I'm using.
/**
Iterates over a query using find(), which is very fast, compared to each().
Works up to 10,000 records maximum.
#param query Parse.Query to iterate.
#param callback Called for each batch of records.
#return Promise, fulfilled when iteration is done.
*/
function findAll(query, callback) {
var queryCount = 0;
var startTime = new Date();
var CHUNK_SIZE=1000;
query.limit(CHUNK_SIZE);
var queryFind = function() {
query.skip(CHUNK_SIZE * queryCount);
queryCount++;
return query.find().then(function(rows) {
callback(rows);
if (rows.length == CHUNK_SIZE) {
return queryFind();
}
});
}
return queryFind();
}
// Example of how to use findAll.
function fetchTree() {
var records = 0;
var query = new Parse.Query('TreeNode');
query.include('scores');
return findAll(query, function(nodes) {
nodes.forEach(function(node) {
records++;
node.get('scores').forEach(function(score, scoreIndex) {
if (!score) {
throw "Null score at row " + node.id + "/" + records + " index " + scoreIndex;
}
});
});
}, true);
}
fetchTree();
Thanks in advance.
Parse limits rows returned per query to a default of 50 with a max of 1000.
This limit includes related records, so if you get 10 records that each have on average 50 pointers in their array and you include() them you are using 500/1000 max records for your query.

MS Dynamics CRM Form Field OnChange check for Existing Value in Entity

Unless someone can explain what I'm missing, CRM 2013 does not have any way to check for a duplicate WHILE entering a new Lead record. I want to check for a duplicate BEFORE the new record is saved. I can't seem to figure this one out.
Basically, when a user enters the Company Name on a new Lead record, I'd like JavaScript or something check for the existence of that value in all the other Lead records and return True or False. That way I can alert the user that the Company already exists BEFORE they save the new record.
Make sense? Am I just TOTALLY missing something here?
Thanks,
Scotty
Microsoft removed this functionality. But you can restore it using one of following articles:
http://a33ik.blogspot.com/2013/10/how-to-turn-on-duplicate-detection-for.html
http://jlattimer.blogspot.com/2013/10/are-you-missing-duplicate-detection-in.html
You can use below function to check duplicate records and set alert/field value depending upon result set :
CheckDuplicate: function (someIdentifier) {
var value = null;
var filter = "?$select=*&$filter=(new_Identifier eq '" + someIdentifier + "') and (new_someGuidField/Id eq guid'" + Xrm.Page.getAttribute("new_someGuidField").getValue()[0].id + "')";
retrieveMultipleSync("new_EntityNameSet", filter, function (data, textStatus, XmlHttpRequest) {
if (data != null && data.length > 0) {
value = data;
}
}, null);
return value;
}

Get all entries for a given name in firefox form history

Is there a way I can find out all elements of a given name in teh form history. In my firefox addon, I am adding some elements in the form-history under a specific name - lest say "search-description".
I now want to get all the elements I added under this name. I see that I can get a history object :
this.Ci = Components.interfaces;
this.Cc = Components.classes;
var historyObj = this.Cc["#mozilla.org/satchel/form-history;1"].getService(this.Ci.nsIFormHistory2 || this.Ci.nsIFormHistory);
But the nsIFormHistory or nsIFormHistory2 interfaces do not have any function like:
getAllEntries(name)
Anyone can help me out in this?
Usually, nsIFormHistory2.DBConnection property is used for querying, you access the SQLite table directly. Something like this (untested):
var completionListener =
{
handleCompletion: function(reason) {},
handleError: function(error) {},
handleResult: function(result)
{
var values = [];
while (true)
{
var row = result.getNextRow();
if (!row)
break;
values.push(row.getResultByName("value"));
}
alert("Autocomplete values: " + values);
}
};
var query = "SELECT value " +
"FROM moz_formhistory " +
"WHERE fieldname='search-description'";
var statement = historyObj.DBConnection.createAsyncStatement(query);
historyObj.DBConnection.executeAsync([statement], 1, completionListener);
Note that using async API is recommended here, querying the database might take time.

Resources