I have the class Friends on Parse:
Class Friends{
"from" : Pointer(_User)
"to" : Pointer(_User)
"allowSee" : Boolean
"block" : Boolean
"createdAt" : Date
"updatedAt" : Date
}
I have a Parse.Query where I get my friends, but this is Class Friends not class User. I try do a cicle for get the users in el field "from" but the array users return void
var user = Parse.User.current();
var me = {__type: 'Pointer',className: '_User', objectId: user.id}
var qFriends = new Parse.Query("Friends");
qFriends.equalTo("to", me);
qFriends.equalTo("allowSee", true);
qFriends.find().then(function(results){
for (i = 0; i < results.length; i++) {
var uFriendId = results[i].get("from").id;
var getUserById = new Parse.Query("_User");
getUserById.equalTo("objectId", uFriendId);
getUserById.first({
success: function(user) {
users.push(user);
},
error: function(error){
console.log(error);
}
})
}
return users;
}).then(function(friends){
response.success(friends);
}, function(error){
response.error();
});
Do exist way of get users by array of objectIds?, example:
var from =["f8dfg3","32fsg5s","43t4gsd"];
var arrUsers = getUser(from); // return array of PFUser with objectId in array from
Thanks,
Because your Friends class keeps pointers to users, there is a good way, in a single step, to eagerly fetch the related users. Before running the query, add:
qFriends.include("from");
qFriends.include("to");
Upon completion, the related users will be fetched, so you can get at them as follows:
qFriends.find().then(function(results){
for (i = 0; i < results.length; i++) {
var friend = results[i];
var fromUser = friend.get("from");
var toUser = friend.get("to");
// these will be fetched, so you can say things like:
console.log(fromUser.username);
// and so on
Incidentally, there's no need to build a pointer from the current user to qualify the query, the current user will do just fine as follows:
qFriends.equalTo("to", Parse.User.current());
Also, your goal should be covered with just the include() advice above, but at some point you might need to query the related objects in the results block the way your original post code attempts. The OP code makes two mistakes there: (1) you can just fetch(result.get("from")), the object -- no need to extract the objectId and call either get() or first() as you do. (2) all of those functions just named are asynchronous. The loop that launches them will terminate before any of them begin, so the line return users; will necessarily return nothing. The correct approach is to fill an array with the fetch()-returned promises and then return a new promise from Parse.Promise.when(fetchPromises);
Related
I am trying to send a Push Notification through Parse Cloud Code when a certain object has been modified - "dirty"
I think I am almost there, but received an error because I believe am creating a new user instead of querying for one.
Parse.Cloud.beforeSave("Fact", function(request, response) {
var dirtyKeys = request.object.dirtyKeys();
for (var i = 0; i < dirtyKeys.length; ++i) {
var dirtyKey = dirtyKeys[i];
if (dirtyKey === "isValid") {
//send push
// Creates a pointer to _User with object id of userId
var targetUser = new Parse.User();
// targetUser.id = userId;
targetUser.id = request.object.userID;
var query = new Parse.Query(Parse.Installation);
query.equalTo('user', targetUser);
Parse.Push.send({
where: query,
data: {
alert: "Your Fact was approved :)"
}
});
return;
}
}
response.success();
});
I found this post related to my problem. My question now is how to integrate the user query in my beforeSave block. Ideally I would create another function for the user query and place that in my beforeSave block.
**5/14 Update
I took #toddg's advice and fixed the before save. Here is a clearer picture of what I am trying to do and the new error.
A couple points (as #Subash noted in the comments) before I get into the code:
Parse.Push.send is an async operation, so you'll want to ensure you call response.success() after your push send completes. I'm going to deal with this using Promises, as I think they are more flexible than callbacks. If you're not familiar, read about them here
The return in your if statement will likely prevent the response.success() from being called.
Here's my recommended way of doing it:
Parse.Cloud.beforeSave("Fact", function(request, response) {
// Keep track of whether we need to send the push notification
var shouldPushBeSent = false;
var dirtyKeys = request.object.dirtyKeys();
for (var i = 0; i < dirtyKeys.length; ++i) {
var dirtyKey = dirtyKeys[i];
if (dirtyKey === "isValid") {
shouldPushBeSent = true;
}
}
if (shouldPushBeSent) {
//send push
// Creates a pointer to _User with object id of userId
var targetUser = new Parse.User();
// targetUser.id = userId;
targetUser.id = request.object.userId;
var query = new Parse.Query(Parse.Installation);
// We want to pass the User object to the query rather than the UserId
query.equalTo('user', targetUser);
Parse.Push.send({
where: query, // Set our Installation query
data: {
alert: "Your fact was approved"
}
}).then(function(){
// Now we know the push notification was successfully sent
response.success();
}, function(error){
// There was an error sending the push notification
response.error("We had an error sending push: " + error);
});
} else {
// We don't need to send the push notification.
response.success();
}
});
By the way, I'm assuming that you have a column on your Installation class that tracks which user is associated with each Installation.
I have a sub query in mongoose need to get array out of sub query and attach to main json out put/ object.
my first query get user info which contains blocked_users array which is nothing but array of user id's.
i my second query we get profile details of blocker_users array and append to main user object in blocked_users.
var userId = ObjectID(req.body.user_id);
//Get user
newUserModel.findById(userId, function(err, user){
if(err){
utils.getResponse(res, req.url, messages.failure, "");
} else {
var userInfo = {};
var blcked_contacts;
//get users details from blocked contacts userid's array
newUserModel.find({'_id': {$in:user.blocked_contacts}}, function (err,blocked_users) {
if(blocked_users){
//blcked_contacts.push(blocked_users);
console.log(blocked_users);
return;
};
/*else{
blcked_contacts = [];
}*/
});
userInfo['blocked_contacts'].push(blocked_users);
userInfo['user_id'] = user.id;
userInfo['country_code'] = user.country_code;
//userInfo['blocked_contacts'].push(blcked_contacts);
//userInfo['blocked_contacts'] = user.blocked_contacts;
var userData = Array();
}
});
Don't really know what you're looking for. But saw a problem in your code. You've assigned the blocked_users to the blocked_contacts field outside the find method.
Since these calls are asynchronous in nature, it might happen that the assignment takes place even before the documents are fetched from MongoDB. So you should write your assignment statements inside the find methods' callback, just the way Medet did.
Noticed few mistakes in your code like trying to use .push on an object. You cant do
userInfo['blocked_contacts'].push(blocked_users); // incorrect as userInfo is an empty object and you dont have an array defined for userInfo['blocked_contacts']
You probably get cannot push into undefined error for this. So instead do
userInfo['blocked_contacts'] = blocked_users;
Also you have to do this inside the second find() as blocked_users is only available inside it. So your final query should be something like
var userId = ObjectID(req.body.user_id);
//Get user
newUserModel.findById(userId, function(err, user){
if(err){
utils.getResponse(res, req.url, messages.failure, "");
} else {
var userInfo = {};
//get users details from blocked contacts userid's array
newUserModel.find({'_id': {$in:user.blocked_contacts}}, function (err,blocked_users) {
if(blocked_users){
userInfo['user_id'] = user.id;
userInfo['country_code'] = user.country_code;
userInfo['blocked_contacts'] = blocked_users; // assign blocked_users into userInfo
console.log(userInfo) // Your required object
} else {
userInfo['user_id'] = user.id;
userInfo['country_code'] = user.country_code;
userInfo['blocked_contacts'] = []; // assign null array if no blocked users fould
}
});
var userData = Array();
}
});
The result of console.log should be an object like this
{
user_id : "..id of searched user...",
country_code : "..country code of searched user..",
blocked_contacts : [<array containing detais of all blocked users>] // null array if no users found
}
I have an iphone app created as a multiplication game and saves the following into a class called 'Results'.
PFObject *Results = [PFObject objectWithClassName:#"Result"];
[Results setObject:levelNumberLabel.text forKey:#"LevelNumber"];
[Results saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) etc.
I also have a class called 'currentUser' that stores the following:
PFObject *currentUser = [PFObject objectWithClassName:#"currentUser"];
[currentUser setObject:_firstnameLabel.text forKey:#"SFirstName"];
I want to run a javascript query that 'links' these two tables. I have a point
er set up called 'currentuser' in the currentUser class and a pointer called 'currentResult'.. These hold no value (undefined).
How am I able to merge these classes together? Will it be a case of linking it through the app or using javascript? I'm slightly confused. Here is my javascript code
var Show = Parse.Object.extend("Result");
var query = new Parse.Query(Show);
query.include('currentUser');
query.find({
success: function(shows) {
for(var i = 0; i < shows.length; i++) {
var show = results[i];
var surname = results.get('SSurname');
console.log(i);
var users = show.get('currentUser');
var username = users.get("SFirstName");
$(".success").append(username + " on " + surname + "<br/>");
Any questions/help please let me know.
Any help on the subject would be greatly appreciated
Parse already gives us a User class (PFUser). Consider starting with that one.
Next, create a class that represents the result of play. "Result" (singular) is an okay name for that. It can have string and number attributes as you see fit. (name those starting with lower case, e.g. "levelNumber"). To associate a result with a user, the Result table must also have a pointer attribute to the User, call it "user".
In Objective-C, when its time to save the result of play:
PFUser *user = [PFUser currentUser]; // this is the signed in PFUser
PFObject *result = [PFObject objectWithClassName:#"Result"];
result[#"user"] = user;
result[#"some_other_col_name"] = some_other_value;
[result saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
// ...
}];
In JS, to find the all of the results created by the play of some user:
// if this is called in a cloud function, the request.user will be
// the PFUser on the client that made the request
function resultsForUser(user) {
var query = new Parse.Query("Result");
query.equalTo("user" user);
return query.find().then(function(results) {
// results are the Result objects whose user is the given user
}, function (error) {
});
}
I am currently working on my own project, based on the discover meteor book.
I have subscriptions of my collection 'posts'.
I am using easy-search (a search package), and currently having some troubles.
I have easy search on a overlay called in with javascript.
When I search, it will always return the posts included in the subscriptions + search result as the result.
For example, if I'm in the post lists page, if I search for Chocolate, the result would be every posts in the post list page + chocolate keyword posts.
It goes the same for single post pages.
I was wondering if I could unsubscribe temporarily with a click event. In this case, would be the search button.
Don't use Meteor.publish for searching.
Create a Meteor.method on the server instead to find the search results.
Create a client-only (unmanaged) collection var results = new Mongo.Collection(null)
When you perform the search, remove all results results.remove({}) and then insert the results from the Meteor.method callback.
Then, to stop each search waiting until the next one completes (bad for autocomplete), you can look at calling the Meteor.method with wait: false eg.
Meteor.apply('mySearchMethod',[parameters], {wait: false}, function(err, res){});
To make this work, you need to call this.unblock() inside the search method.
Example Code
var searching = new ReactiveVar(false);
var currentSearch = "";
var results = new Mongo.Collection(null);
var search = function(searchText){
searchText = searchText.trim();
if (searchText === currentSearch){
// abort search if query wasn't different
return;
}
// clear results immediately (don't show expired results)
// NOTE: this can cause "flicker" as results are removed / re added
results.remove({});
if (searchText === ""){
return;
}
searching.set(true);
performSearch(searchText)
};
var performSearch = _.debounce(function(searchText){
currentSearch = searchText;
Meteor.apply('mySearchMethod', [searchText], {wait: false}, function(err, res){
if (err){
console.error(err);
}
if (currentSearrch !== searchText){
// query changed, results aren't relevant
return;
}
for (var i = 0; i < res.length; i++){
results.insert(res[i]);
}
searching.set(false);
})
}, 300);
Template.myTemplate.events({
'input #mySearchBox': function(e){
search($(e.currentTarget).val());
}
});
Template.myTemplate.heplers({
'searchResults': function(){
return results.find();
},
'showSpinner': function(){
return searching.get();
}
})
if (Meteor.isServer){
Meteor.methods({
'mySearchMethod': function(searchText){
check(searchText, String);
this.unblock();
var searchExp = new RegExp(RexExp.escape(searchText), 'i');
return myCollection.find({myField: searchExp}).fetch();
}
});
}
I am trying to add hashtags in the post's hashtag[] array as a object with a num:1 variable to the users hashtagseen[] array if it is not already in it else add 1 the num if the hashtag is already in the hashtagseen[] array. How do I fix my code? Here is the code, thanks in advanced.
edit: I think I am not finding post.hashtag with this.hashtag and that is why it will not go to else. Just a guess.
The user object
Accounts.createUser({
username: username,
password: password,
email: email,
profile: {
hashtagsl:[],
}
});
collections/post.js
var post = _.extend(_.pick(postAttributes, 'title', 'posttext','hashtags'), {
userId: user._id,
username: user.username,
submitted: new Date().getTime(),
commentsCount: 0,
upvoters: [], votes: 0,
});
calling it
Meteor.call('addposthashtags',this.hashtags,Meteor.user().profile.hashtagsl);
lib/usershash
Meteor.methods({
addposthashtags: function (hashtags,hashtagsl) {
//supposed to make hashtagseen a array with the names from the hashtagsl object in it
var hashtagseen = _.pluck(hashtagsl, 'name');
//supposed to run once per each hashtag in the posts array.
for (var a = 0; a < hashtags.length; a++) {
//supposed set hashtagnumber to the number indexOf spits out.
var hashnumber=hashtagseen.indexOf(hashtags[a]);
//supposed to check if the current hashtag[a] === a idem in the hashtagseen.
if(hashnumber===-1){
var newhashtag = this.hashtags[a];
//supposed to make the object with a name = to the current hashtags
Meteor.users.update({"_id": this.userId},{"$push":{"profile.hashtagsl": {name: newhashtag, num: 1}}})
} else {
var hashi = hashtagseen[hashnumber];
//supposed to ad one to the num variable within the current object in hashtagsl
Meteor.users.update({"_id": this.userId, "profile.hashtagsl.name":hashi},{"$inc":{"profile.hashtagsl.num":1}});
}
}
}
});
Your addposthashtags function is full of issues. You also haven't provided a "schema" for hashtag objects.
addposthashtags: function () {
for (a = 0; a < this.hashtag.length; a++) {
// Issue1: You're querying out the user for every iteration of the loop!?
for (i = 0; i < Meteor.user().profile.hashtagseen.length; i++) {
// Issue2: You're comparing two _objects_ with ===
// Issue3: Even if you use EJSON.equals - the `num` property wont match
// Issue4: You're querying out the user again?
if (this.hashtag[a] === Meteor.user().profile.hashtagseen[i]) {
// Issue5 no `var` statement for hashtagseeni?
// Issue6 You're querying out the user again??
hashtagseeni = Meteor.user().profile.hashtagseen[i];
//Issue7 undefined hashtagsli?
//Issue8 Calling multiple methods for the one action (eg in a loop) is a waste of resources.
Meteor.call('addseen', hashtagsli);
} else {
//Issue9 no `var` statement for newhashtag?
newhashtag = this.hashtag[a];
newhashtag.num = 1;
//Issue8b Calling multiple methods for the one action (eg in a loop) is a waste of resources.
Meteor.call('updateUser', newhashtag, function (err, result) {
if (err)
console.log(err);
});
}
}
}
}
Also, the method has similiar issues:
addseen: function (hashtagseeni) {
// Issue10: var `profile` is undefined
// Issue11: should use `this.userId`
// Issue12: hashtagseeni wouldn't match profile.hashtagseen due to "num" field.
Meteor.users.update({"_id": Meteor.userId, "profile.hashtagseen": profile.hashtagseeni}, {"$inc":{"profile.hashtagseen.$.num":1}});
}
New issues with your new set of code:
Meteor.methods({
addposthashtags: function (hashtags,hashtagsl) {
//Issue1 `hashtag` is undefined, guessing you mean `hashtags`
//Issue2 no `var` for a
for (a = 0; a < hashtag.length; a++) {
//Issue3 no `var` for i
//Issue4 Why are you looping through both?
// don't you just want to check if hashtag[a] is in hashtagsl?
for (i = 0; i < hashtagsl.length; i++) {
if (hashtags[a] === hashtagsl[i].name) {
var hashi = hashtagsl[i].name;
//supposed to ad one to the num variable within the current object in hashtagsl.
// Issue5: This query wont do what you think. Test until you've got it right.
Meteor.users.update({"_id": Meteor.userId, 'profile.hashtagsl':hashi}, {"$inc":{"num":1}});
} else {
// Issue6 `this.hashtag` isn't defined. guessing you mean `hashtags[a]`
var newhashtag = this.hashtag[a];
// Issue7 superfluous statement
var newhashtagnum = num = 1;
// Issue8 Obvious syntax errors
// Perhaps try Meteor.users.update({"_id": this.userId},{"$push":{"profile.hashtagsl": {name: newhashtag, num: 1}}})
Meteor.users.update({"_id": Meteor.userId, 'profile'},{"$addToSet":{"hashtagsl"[newhashtag]=newhashtagnum}})
};
};
};
};
});
I'd suggest you trying the following
1) Assuming that after newhashtag=hashtag[a] you get a JSON object in newhashtag variable, try replacing newhashtag:{num:1}; with newhashtag.num = 1 - this will add the num variable to the object and set the value.
1.a) For debugging purposes try adding some console.log(JSON.stringify(newhashtag)); after each of the two lines where you're setting and changing the newhashtag variable - this way you'll know exactly what you're trying to add to the mongoDB document.
2) The update to increment the views also doesn't seem to me that will work. Couple of things to note here - $set:{'profile.hashtagseen[i]':num++} - MongoDB won't be able to identify the 'i' in 'profile.hashtagseen[i]' and 'num++' is not how increments are done in Mongo.
I'd suggest you look into the $inc and to the positional update documentation of MongoDB.
Your final increment update statement will look something like
Meteor.users.update({"_id": Meteor.userId, "profile.hashtagseen": profile.hashtagseen[i]}, {"$inc":{"profile.hashtagseen.$.num":1}});
I see that executing addposthashtags is in the client, and you must to pay attention because this function will execute in minimongo and doesn't work all operations. First you try execute this operation under mongo if it's work you must to create one function inside the folder server.
Add text of the documentation of Minimongo
In this release, Minimongo has some limitations:
$pull in modifiers can only accept certain kinds of selectors.
findAndModify, aggregate functions, and map/reduce aren't supported.
All of these will be addressed in a future release. For full Minimongo
release notes, see packages/minimongo/NOTES in the repository.
Minimongo doesn't currently have indexes. It's rare for this to be an
issue, since it's unusual for a client to have enough data that an
index is worthwhile.
You try create one method on the server, with the same operation.
Server:
Meteor.methods({
updateUser: function (newhashtag) {
Meteor.users.update(this.userId,
{
$addToSet: {'profile.$.hashtagseen': newhashtag}
});
}
});
Client:
Meteor.call('updateUser',newhashtag,function(err,result){
if (err)
console.log(err);// there you can print the erro if there are
});
Minimongo doesn't support alls operation, for test you can to execute in the console for testing the method if supported. After that you can to execute the operation under mongo directly, that clears your doubts.