I currently have this cloud code to retrieve all the users that have a relation with the current user. I have to first find the current user then query the "Friends" column hence the relational query step.
The line response.success(results) returns all the attributes of all of the current user's friends. I only want a few of the columns that belong to these friends, not every single thing they saved when signing up.
Parse.Cloud.define("getFriends", function(request, response) {
var userId = request.params.UserKey;
var query = new Parse.Query(Parse.User);
query.ascending("updatedAt");
query.get(userId, {
success: function(foundCurrentUser) {
var currentUser = foundCurrentUser;
var relation = currentUser.relation("Friends");
var getRelationQuery = relation.query();
getRelationQuery.find().then(function(results) {
response.success(results);
});
},
error: function(error) {
response.error(error);
}
});
});
I am using swift to to use the response, I am not sure that if I need to tweak the swift code but will provide it anyway.
func LoadCarpoolersFromParse(Success:(object:AnyObject)->(),Failure:(error:NSError)->())
{
let params = NSMutableDictionary()
params.setObject(PFUser.currentUser()!.objectId!, forKey: "UserKey")
PFCloud.callFunctionInBackground("getCarpoolers", withParameters: params as [NSObject : AnyObject], block: {
(response:AnyObject?, error: NSError?) -> Void in
if error == nil {
Success(object: response!)
}
else{
Failure(error:error!)
}
})
}
}
You can do it by using select method of Parse.Query, make the following changes in your cloud code
Parse.Cloud.define("getFriends", function(request, response) {
var userId = request.params.UserKey;
var query = new Parse.Query(Parse.User);
query.ascending("updatedAt");
query.select("name","phone"); // replace with your required fields
Related
The database has a class "Photos". This class has a pointer to "User" class.
I use this cloud code:
Parse.Cloud.define("AllPhotos", function(request, response) {
var query = new Parse.Query("Photos");
var userPointer = {"__type":"Pointer","className":"User","objectId":request.params.userId};
query.equalTo("active", true);
query.equalTo("userId", userPointer);
query.descending("createdAt");
query.include("_User");
query.find({
success: function(results) {
response.success(results);
},
error: function() {
response.error("Error 000");
}
});
});
When I query "AllPhotos" I expected to get the User object (with username, name etc) without another query but this is the result:
<Photos: 0x6080004a0240, objectId: k2SvMOVJ7s, localId: (null)> {
active = 1;
image = "<PFFile: 0x60800064cdb0>";
likes = 0;
userId = "<PFUser: 0x6080002e9300, objectId: gHfS6dzrag, localId: (null)>";
}
It just give me the objectId and I need to query again the user class to get username and name.
How can I retrieve without doing another query?
What type is userId? It looks like your userId is actually a pointer to the user? If so, you need to call query.include("userId"), not query.include("_User"). _User is the under the hood class of Parse.user. WHen you use include, you need to include the field name a pointer is stored under.
I have a table called "Current1", which I am saving user's object as pointer like this:
When I click on this pointer I direct to _User table. Now I am trying to do very simple query. I need to access to username inside user pointer and later update something in _User table.
My problem is now to access 'username' in '_User' table by using a pointer:
var aveGame2 = Parse.Object.extend("Current1");
var query2 = new Parse.Query(aveGame2);
query2.include("user");
query2.find({
success: function(results) {
for (var i = 0; i < results.length; i++)
{
var object = results[i];
//....
var user = object.get('user');
var username = user.get('username'); //<--Error is pointing to this line
//More operation
if(True)//Some conditions
{
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.equalTo("username", username);
// Get the first user which matches the above constraints.
query.first({
success: function(anotherUser) {
anotherUser.set("prize", 10);
// Save the user.
anotherUser.save(null, {
success: function(anotherUser) {
// The user was saved successfully.
response.success("Successfully updated user.");
},
error: function(gameScore, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
response.error("Could not save changes to user.");
}
});
},
error: function(error) {
response.error("Could not find user.");
}
});
Error:
[Error]: TypeError: Cannot call method 'get' of undefined
at e.query2.find.success
After hours of checking each fields I realised I have not set ACL for _User table as Public read. This might help someone else.
I'm trying to query whether a PFUser exists in another PFUser's 'blockedUsers' relation column before sending a push notification:
I have written this but it doesn't seem to be working:
var recipientBlockList = toUser.relation("blockedUsers");
var blockListQuery = Parse.Query(recipientBlockList);
blockListQuery.contains(fromUser);
blockListQuery.find({
success: function(users) {
},
error: function() {
}
});
For relation object queries, you should use yourRelation.query():
var blockListQuery = recipientBlockList.query();
As documentation says - "The JavaScript SDK does not currently support modifying Installation objects.", but what about creating these objects? is it possible to create Installation objects from cloud code?
For ex:
Parse.Cloud.define("registerForNotifications", function(request,response) {
var token = request.params.deviceToken;
var deviceType = request.params.deviceType;
var user = request.user;
var installation = new Parse.Object("Installation");
if (installation) {
installation.set("deviceToken",token);
... so on..
installation.save();
}
});
Will this work? Thank you.
Some example:
//The following Cloud Function expects two parameters: the channel to be added to this user's installations, and the object id for the user.
//It assumes that each installation has a `Pointer <_User>` back to the original user.
//...
Parse.Cloud.define("subscribeToChannel", function(request, response) {
var channelName = request.params.channel;
var userId = request.params.userId;
if (!channelName) {
response.error("Missing parameter: channel")
return;
}
if (!userId) {
response.error("Missing parameter: userId")
return;
}
// Create a Pointer to this user based on their object id
var user = new Parse.User();
user.id = userId;
// Need the Master Key to update Installations
Parse.Cloud.useMasterKey();
// A user might have more than one Installation
var query = new Parse.Query(Parse.Installation);
query.equalTo("user", user); // Match Installations with a pointer to this User
query.find({
success: function(installations) {
for (var i = 0; i < installations.length; ++i) {
// Add the channel to all the installations for this user
installations[i].addUnique("channels", channel);
}
// Save all the installations
Parse.Object.saveAll(installations, {
success: function(installations) {
// All the installations were saved.
response.success("All the installations were updated with this channel.");
},
error: function(error) {
// An error occurred while saving one of the objects.
console.error(error);
response.error("An error occurred while updating this user's installations.")
},
});
},
error: function(error) {
console.error(error);
response.error("An error occurred while looking up this user's installations.")
}
});
});
I'm creating a push notification similar to this sample code provided by Parse:
Parse.Cloud.afterSave('Activity', function(request) {
if (request.object.get("type") === ("comment") {
var message = request.user.get('displayName') + ': ';
message += request.object.get('content').trim();
var query = new Parse.Query(Parse.Installation);
query.equalTo('user', request.object.get("toUser"));
Parse.Push.send({
where:query,
data: {
alert: message,
badge: 'Increment'
}
});
}
});
My question is: in the data area of the Parse.Push.send, can I send an entire message object, where Message is a custom class I created? If so, what would that look like?
If you already have the class created and saved an object why not just send the object ID and query it asynchronously once the user goes to retrieve the push notification?
The message object does not need to waste up space and be sent via push just a pointer is required.
I'm in the process of implementing something similar and this is the route I plan to use.
You can serialize the object in JSON/XML format and then deserialize it when you receive the push notification.
You can't send objects directly. You'll get an exception (I had this issue a few days ago but didn't write the name of the exception down). The best answer is so far is by BrentonGray88.
I'm assuming you're not using Android because you included the badge: "Increment" value, but this is how I would do it:
Android code to send the notification:
Make sure the Comment object has a pointer (_User) column to the User who sent the comment. When you create the comment, include user.put("commentAuthor", ParseUser.getCurrentUser()); in your Android code so that you can always access the user who created the comment.
Now you need to query the Comment to send its objectId through to the push notification.
ParseQuery<ParseObject> query = new ParseQuery<>("Comment");
query.whereEqualTo("objectId", I AM NOT SURE WHAT CONDITION YOU WANT HERE);
query.findInBackground((comment, e) -> {
if (e == null) for (ParseObject commentObject: comment) {
String recipientObjectId = commentObject.getParseObject("commentAuthor").getObjectId();
final Map<String, Object> params = new HashMap<>();
// This is to send the notification to the author of the Comment
params.put("recipientObjectId", recipientObjectId);
// This is so we can use values from the Comment in the notification
params.put("commentObjectId", commentObject.getObjectId());
// This is a required lined
params.put("useMasterKey", true);
ParseCloud.callFunctionInBackground("pushMessage", params, new FunctionCallback<String>() {
public void done(String result, ParseException e) {
if (e == null) {
Log.d(getClass().toString(), "ANNOUNCEMENT SUCCESS");
} else {
System.out.println(e);
Log.d(getClass().toString(), "ANNOUNCEMENT FAILURE");
}
}
});
}
});
Now for the query in your Cloude Code:
Parse.Cloud.define("pushMessage", function (request, response) {
// Again, we are sending the notification to the author of the Comment
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo('user', request.params.get("recipientObjectId"));
// We retrieve information from the Comment created by that author
var commentQuery = new Parse.Query(Parse.Comment);
commentQuery.equalTo('objectId', request.params.commentObjectId);
commentQuery.get("commentObjectId", {
success: function(userObject) {
var displayName = userObject.get("displayName");
var content = userObject.get("content");
var message = displayName + ': ';
message += content.trim();
Parse.Push.send({
where: pushQuery,
data: {
alert: message
},
}, {
useMasterKey: true,
success: function () {
response.success("Success!");
},
error: function (error) {
response.error("Error! " + error.message);
}
});
console.log();
},
error: function(error) {
console.log("An error occured :(");
}
});
});
Sorry I'm not the best at JavaScript but that's kind of how I'd do it. Best of luck! :)