Parse cloud code - modifying all PFUsers - javascript

I'm trying to create a cloud Job that takes the users full name or username and saves it in lower case in another column. here's what I have so far:
Parse.Cloud.job('normaliseUsername',function(request, status) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.find({
success: function(items){
for (var i=0;i<items.length;i++) {
var user = items[i];
console.log(user);
var changed = user["nameChanged"];
if (changed === true) {
var username = user.username;
user.set("lowerCaseName",username.toLowerCase());
} else {
var realName = user["firstName"] + " " + user["lastName"];
user.set("lowerCaseName",realName.toLowerCase());
}
user.save();
}
}
});
});
This results in a new column, lowerCaseName, full of undefined.
how do I access properties of a PFUser in this instance? I have tried using user.get(''); but it says Cannot call method 'get' of undefined

Do it this way :
Parse.Cloud.job("normaliseUsername", function(request, status) {
Parse.Cloud.useMasterKey();
var count_user = 0;
var query = new Parse.Query(Parse.User);
query.descending('updatedAt');
query.Exist('nameChanged');
query.limit(1000);
return query.find().then(function(users) {
return Parse.Promise.when(users.map(function(user) {
count_user+= 1;
if (user.get("nameChanged")) {
user.set("canonical_firstname", user.get("username").toLowerCase());
} else {
var realName = user.get("firstname") + ' ' + user.get("lastname");
user.set("lowerCaseName", realName.toLowerCase());
}
return user.save();
}));
}).then(function() {
status.success("normaliseUsername with " + count_user + " user(s) updated.");
}, function(error) {
status.error("Uh oh, something went wrong.");
});
});
Your loop with for, will never works, you need to use Promise. More information here : http://blog.parse.com/learn/engineering/whats-so-great-about-javascript-promises/
The way the above script works, you will work with Promise in Parallel, not in Series : https://parse.com/docs/js/guide#promises

Related

Missing ) after argument list (Node)

I'm using Node to run this program, where is my error(s)? It's saying I'm missing ) after argument list. I can't find where this error is, I've tried putting the ) in various places. I'm using Node v5
var Twit = require('twit');
var T = new Twit(require('./config.js'));
var stream = T.stream('statuses/filter', {
track: 'xoxo, oi, i\m fine,'
});
(stream.on('tweet', function(tweet) {
console.log('#' + tweet.user.screen_name + ': ' + tweet.text);
if (tweet.text.indexOf('RT') > -1) {
return;
}
var replyString;
if (tweet.user.utc_offset === null) {
replyString = ' Ok';
} else {
replyString = ' Okay';
}
})
(T.post('statuses/update', {
status: '#' + tweet.user.screen_name + replyString,
in_reply_to_status_id: tweet.id_str
}, function(err, data, response) {
if (err) {
console.log(err);
return;
}
}
tweet.botReplyId = data.id_str);
db.tweets.insert(tweet);
});
(end)
})
setInterval(stream, 60000);
The code seems to be a bit all over the place with regards to scope and it makes it a bit difficult to follow.
Try using something like the following which annotates it a bit and should help avoid issues like this (as it seems to validate without any errors) :
// Define your variables
var Twit = require('twit');
var T = new Twit(require('./config.js'));
var stream = T.stream('statuses/filter', { track: 'xoxo, oi, i\'m fine,'});
// When a tweet occurs
(stream.on('tweet', function(tweet) {
// Log it
console.log('#' + tweet.user.screen_name + ': ' + tweet.text);
// Determine if it is a retweet and ignore
if (tweet.text.indexOf('RT') > -1) { return; }
// Set your reply
var replyString = (tweet.user.utc_offset === null) ? ' Ok' : ' Okay';
// Post your reply
T.post('statuses/update', { status: '#' + tweet.user.screen_name + replyString, in_reply_to_status_id: tweet.id_str}, function(err, data, response) {
// If an error occurs, log it
if (err) {
console.log(err);
return;
}
// Otherwise store your response and store it
tweet.botReplyId = data.id_str;
db.tweets.insert(tweet);
});
}));
// Check your stream every 10 minutes
setInterval(stream, 60000);

Parse "Unexpected identifier in main.js" in my Cloud Code

I am trying to deploy my newly written cloud code function to Parse but I keep getting the error "Unexpected identifier" at line 110, I can't seem to figure out how there is an error here, any help?
Parse.Cloud.define("backgroundJob", function(request, response) {
Parse.Cloud.useMasterKey();
var moments = require("cloud/moments.js");
var now = moments.moment();
var groupObject = Parse.Object.extend("Group");
var query = new Parse.Query(groupObject);
var eventObject = Parse.Object.extend("Event");
query.find().then(function(groups) {
var promise = Parse.Promise.as();
_.each(group, function(result) {
promise = promise.then(function() {
var count = 0;
var events = _.map(result.get("Events"), function(eventArray) {
if (now == eventArray[count].get('date') {
var curEvent = eventArray[count];
eventArray[count].destory();
var relationc = result.get("created");
var createdq = relationc.query();
var relationj = result.get("created");
var joinedq = relationj.query();
var partOnee = curEvent.get("name");
var outString = partOnee.concat(" is now");
Parse.Push.send({
where: createdq,
data: {
alert: outString
}
}).then(function() {
response.success();
}, function(error) {
response.error(error);
});
Parse.Push.send({
where: joinedq,
data: {
alert: outString
}
}).then(function() {
response.success();
}, function(error) {
response.error(error);
});
}
count = count+1;
});
});
});
}).then(function() {
response.success()
}, function(error) {
response.error(error);
});
});
Line 110 is var curEvent = eventArray[count];
You missed ) in this line if (now == eventArray[count].get('date'), see:
var events = _.map(result.get("Events"), function(eventArray) {
if (now == eventArray[count].get('date') {
Fix:
var events = _.map(result.get("Events"), function(eventArray) {
if (now == eventArray[count].get('date')) {
Note, when interpreters/compilers (in most programming languages) say there is a problem on a line, usually the problem can be in any row before.

Parse .each() does not work within when()

Parse.Cloud.define("bulkUpdateUserViewedTraces", function(request, response){
Parse.Cloud.useMasterKey();
var userQuery = new Parse.Query(Parse.User);
userQuery.limit(200);
var userCount = 0;
userQuery
.find(function (users) {
var promises = _.map(users, function (user){
userCount++;
return populateViewedTraces(user);
});
return promises;
})
.then(function (promises) {
return Parse.Promise.when(promises);
})
.then(function(){
console.log("Processed " + userCount + " users");
response.success("Processed " + userCount + " users");
}, function(error){
console.error(JSON.stringify(error));
response.error(error);
});
});
function populateViewedTraces (user) {
var viewedTracesCount = 0;
var viewHistoryQuery = new Parse.Query("ViewHistory");
viewHistoryQuery.equalTo("user", user);
return viewHistoryQuery
.each(function (viewHistory) {
console.log("Got here");
viewedTracesCount++;
})
.then(function () {
console.log("Got here 2");
return user.save();
});
}
Doesnt work. Logs "Processed x users" but never logs "got here". The promises should execute during the when() call, but never do.
This makes absolutely no sense as every post I've seen describing when is written like this. For some reason this just doesnt do anything.

Trying to get interval function to work with my factory

I create a factory where I put my http request for adding, retrieving and deleting tasks.
Now when I add a task you don't see the visual change. I have to refresh the browser. Now to fix this I figured I would write a function to check the length of the old array against the length of the new one and set an interval off 1 minutes on it to make this change and then pull in the tasks. I am able to log my length change of the array but nothing happens visually (still have to refresh the browser).
If anybody could help me out here.
Part of my app.js code:
global vars -> defaultStart, defaultEnd, clickDate
zazzleApp.factory('TaskService', function ($http) {
var TaskService = {};
TaskService.taskList = [];
TaskService.getTasks = function(cb){
$http.get('api/task/all')
.success(function(dataFromServer){
for (var i = 0; i < dataFromServer.length; i++) {
TaskService.taskList[i] = dataFromServer[i];
};
//console.log('LOGGING GET_TASK ', TaskService.taskList);
if(cb){
cb(dataFromServer);
}else{
return dataFromServer;
}
//return dataFromServer;
})
.error(function(errorFromServer){
//something went wrong, process the error here
console.log("Error in getting the users from the server ", errorFromServer);
})
};
TaskService.addTask = function(pTask){
var newClickDate = clickDate;
console.log('LOGGGING NEW CLICK DATE = ', newClickDate);
var newEditId = editId;
//console.log('LOGGGING NEW edit id = ', newEditId);
var url;
if (newEditId) {
url = 'api/task/update/' + newEditId;
} else {
url = 'api/task/create';
}
//console.log("URL URL USA", url, newEditId, newClickDate);
defaultStart = new Date(newClickDate);
defaultStart = defaultStart.getFullYear() + "-" + (defaultStart.getMonth() + 1) + "-" + defaultStart.getDate();
defaultStart += " 00:00:00";
defaultEnd = new Date(newClickDate).addDays(1);
defaultEnd = defaultEnd.getFullYear() + "-" + (defaultEnd.getMonth() + 1) + "-" + defaultEnd.getDate();
defaultEnd += " 00:00:00";
console.log('LOGGING DEFAULT START AND DEFAULT END ' , defaultStart, defaultEnd);
pTask.color = $('#containerColorPicker').attr('ng-data-id');
// returns makes sure the promis is returned from the server
return $http.post(url, {
'name': pTask.project_name,
'project_id': pTask.project_type,
'location_id': pTask.location,
'estimate_time': pTask.estimate_time || 2,
'project_client_name': pTask.project_client_name,
'url': pTask.url,
'resource_link': pTask.resource_link,
'notes': pTask.notes,
'start_time': pTask.start_time || defaultStart,
'end_time': pTask.end_time || defaultEnd,
/*'start_time': defaultStart,
'end_time': defaultEnd,*/
'color': pTask.color
}, {
headers: {
"Content-Type": "text/plain"
}
})
.success(function(data, status, headers, config) {
console.log(data);
TaskService.getTasks();
TaskService.taskList.push(data);//pushing the new task
//console.log("YYYYYYYYYYYYY -------->>>>>", defaultStart);
})
.error(function(data, status, headers, config) {
console.log("Failed to add the task to DB");
});
};
TaskService.deleteTask = function (){
var newEditId= editId;
$http.delete('api/task/delete/' + newEditId)
.success(function(dataFromServer){
console.log('logging edit id in delete taks func server ', newEditId);
var index;
for (var i = 0; i < TaskService.taskList.length; i++) {
if(TaskService.taskList[i]._id == newEditId){
//index = i;
console.log ("removing the element from the array, index: ", newEditId, i);
TaskService.taskList.splice(i,1);
}
};
/* if(editId !== -1){
console.log ("removing the element from the array, index: ", editId, index);
UserService.userList.splice(index,1);
}*/
console.log('TaskArray ', TaskService.taskList)
$('div[ng-data-id="'+ newEditId +'"]').remove();
})
.error(function(errorFromServer){
//something went wrong, process the error here
console.log("Error in deleting a user from the server");
})
};
return TaskService;
})
//START CONTROLLER
angular.module('zazzleToolPlannerApp')
.controller('CalendarCtrl', function ($scope, $mdDialog, $http, $rootScope, $timeout, User, Auth, UserService, TaskService) {
$scope.newTask = {};
$scope.newTask.project_name = "";
$scope.newTask.project_type = "";
$scope.newTask.location = "";
$scope.newTask.estimate_time = "";
$scope.newTask.project_client_name = "";
$scope.newTask.url = "";
$scope.newTask.resource_link = "";
$scope.newTask.notes = "";
$scope.newTask.color = "";
$scope.tasks = TaskService.taskList;
$scope.getTasksFromService = function () {
TaskService.getTasks(); //after this gets called, the data will be shown in the page automatically
}
$scope.getTasksFromService();
$scope.addTaskWithService = function () {
//note that you can process the promise right here (because of the return $http in the service)
TaskService.addTask($scope.newTask)
.success(function(data){
//here you can process the data or format it or do whatever you want with it
console.log("Controller: the task has been added");
$scope.tasks = [];// EMPTY THE ARRAY
$scope.tasks = TaskService.getTasks();
//console.log('Taskservice Controller ', $scope.updateGridDataAwesome);
})
.error(function(data){
//something went wrong
console.log("Controller: error in adding task");
});
}
$scope.deleteTaskWithService = function(){
TaskService.deleteTask();
}
TaskService.getTasks(function(data){
$scope.tasks = data;
});
var interval = setInterval(function(){
var oldLength = $scope.tasks.length;
TaskService.getTasks(function(data){
console.log('lengths', oldLength, data.length)
if(oldLength != data.length){
//$scope.tasks = data;
//TaskService.taskList.push(data);
$scope.tasks = TaskService.getTasks();
}
});
}, 6000)
This might be what you're looking for, by using $interval you can set an interval every x seconds:
$interval(function() {
// Something to be executed after 1min (60000ms)
}, 60000);
And then inject $interval into your factory:
zazzleApp.factory('TaskService', function ($http, $interval).....
Try this:
$http
.post("/api/pin", {})
.success(function(data) {
$scope.$apply(function() {
$scope.pins.push(data);
});
});
reference: https://stackoverflow.com/a/24836089/3330947
Update:
I did it like this:
Service (fetch all accounts):
.factory('accountService', function ($http) {
var accountObj = {
async: function () {
var promise = $http.get('account/').then(function (response) {
return response;
});
return promise;
}
};
return accountObj;
})
Controller:
//Call get accounts service and put all accounts in $scope.accounts
var getAccounts = function () {
accountService.async().then(function (d) {
$scope.accounts = d.data;}
}
//Create new account and update array of accounts
$scope.createAccount = function () {
$scope.data = {
'id' : 0,
'customerId' : $scope.outputCustomer[0].id,
'camsId' : $scope.outputCams[0].id,
'camsPin' : parseInt($scope.camsPin),
'username' : $scope.username,
'password' : $scope.password,
'email' : $scope.email,
'acfUsername' : $scope.acfUsername,
'accountActive' : $scope.accountActive,
'agentId' : $scope.outputAgent[0].id,
'freeswitchIds' : freeswitchIds
};
$http.post('account/save', $scope.data).success(
function (data, status) {
$scope.accounts.push(data);
}).error(function () {
});
};
My add function is in controller, i thin it can be redone to be service but this work soo
The problem may be in success of addTask. TaskService.getTaskis async. So the execute order will be: 1. http request in TaskService.getTasks 2. TaskService.taskList.push(data); 3. $http success callback.
.success(function(data, status, headers, config) {
console.log(data);
TaskService.getTasks();
TaskService.taskList.push(data);//pushing the new task
//console.log("YYYYYYYYYYYYY -------->>>>>", defaultStart);
})
In this order, step 2 is pointless. Because step 3 code may override TaskService.taskList
for (var i = 0; i < dataFromServer.length; i++) {
TaskService.taskList[i] = dataFromServer[i];
};
And another wrong place:
$scope.tasks = TaskService.getTasks();
this line code appears twice. But TaskService.getTasks() returns undefined because you don't put keyword return.
In addition, your practice to use promise is wrong. $http leverages promise specification. Don't use callback since you used promise. You may need read promise docs.

How to query in loop to fetch all data from class

I have a class with (currently) 1567 objects. They are urls,title and publication dates of article which I parse from RSS feeds of websites. The cloud job is periodic, so the objects keep on increasing. Although I check for uniqueness in beforesave, from time to time some duplicate items creep up, approximately 10% of objects are duplicate.
I have been trying to make a job to delete these duplicates and want to make a query logic which can get ALL the objects at once. The maximum limit of query is 1000. I referred to this question on Parse Help, and tried to convert it into JavaScript cloud code.
Parse.Cloud.job("DeleteDuplicate", function(request, status) {
var query = new Parse.Query(NewsArticle);
var allObjectArray= [];
var limit = 1000;
var skip = 0;
var repeat = true;
query.limit(limit);
query.skip(skip);
do{
query.find({
success: function(results) {
allObjectArray.push(results.concat());
if(results.length === limit){
skip = skip+limit;
query.skip(skip);
repeat = true;
console.log("true");
}else{
repeat = false;
console.log("false");
}
console.log("Successfully retrieved " + results.length);
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
status.error("Error: " + error.code + " " + error.message);
}
});
}while(repeat);
status.success("final length "+allObjectArray.length);
});
The code fails with the Job Status of "Could not connect to Cloud Code". I think it goes to infinite loop and times out after 2-3 minutes. If anyone can help, that would be great.
EDIT: Can using Promise help?
EDIT 2: Been trying Promise now -
Parse.Cloud.job("jobFindAll", function(request, status) {
var query = new Parse.Query(NewsArticle);
var allObjectArray= [];
var limit = 1000;
var skip = 0;
var repeat = false;
query.limit(limit);
query.skip(skip);
var promiseList = [];
console.log("in job");
query.find().then(function(results) {
console.log("results.length "+results.length);
allObjectArray = results.slice();
console.log("allObjectArray.length "+allObjectArray.length);
if(results.length === limit){
console.log("smaller");
skip = skip+limit;
do{
console.log("first repeat = "+repeat);
promiseList.push(functionFindAll(allObjectArray, limit, skip));
console.log("promiseList - "+promiseList);
repeat = promiseList[promiseList.length-1];
console.log("looping repeat = "+repeat);
}while(repeat);
return Parse.Promise.when(promiseList);
}else{
console.log("longer");
}
}).then(function(){
console.log("in then");
status.success("final length "+allObjectArray.length);
}, function(error) {
status.error("Error: " + error.code + " " + error.message);
}
);
});
function functionFindAll(allObjectArray, limit, skip){
var returnPromiseList = [];
var query_new = new Parse.Query(NewsArticle);
query_new.limit(limit);
query_new.skip(skip);
query_new.find().then(function(results) {
console.log("function results.length "+results.length);
if(results.length === limit){
skip = skip+limit;
query.skip(skip);
allObjectArray.push(results.concat());
console.log("true in function");
return Parse.Promise.as(true);
}else{
allObjectArray.push(results.concat());
return Parse.Promise.as(false);
console.log("false in function");
}
},
function(error) {
console.log("Error: " + error.code + " " + error.message);
return Parse.Promise.as("ERROR!");
}
);
console.log("below "+allObjectArray.length);
}
Now the code doesnt enter the query_new.find(). The log messages in the function doesnt appear, directly the message "below...." appears.
The following code will find all the items in the class, it does not use skip because parse.com has another freaking limit call "unable to skip more than 10000 items". it skip using the objectId.
Parse.Cloud.job("findAll", function(request, status) {
var result = [];
var processCallback = function(res) {
result = result.concat(res);
if (res.length === 1000) {
process(res[res.length-1].id);
return;
}
// do something about the result, result is all the object you needed.
status.success("final length " + result.length);
}
var process = function(skip) {
var query = new Parse.Query("NewsArticle");
if (skip) {
console.log("in if");
query.greaterThan("objectId", skip);
}
query.limit(1000);
query.ascending("objectId");
query.find().then(function querySuccess(res) {
processCallback(res);
}, function queryFailed(reason) {
status.error("query unsuccessful, length of result " + result.length + ", error:" + error.code + " " + error.message);
});
}
process(false);
});
All JS calls in Parse are asynchronous, so your function is spawning infinite threads (even if it was synchronous, your query.skip(skip) would need to go inside the while loop not before it.
Try moving the query out to its own function, which is called recursively on success until you have read all of your objects. You should be able to adapt the code in this answer, which is for a similar problem: https://stackoverflow.com/a/17268263/1176247

Categories