Query entire class vs first object in the class - javascript

In my cloud code I want to retrieve the first object in the "Messages" class. Then i want to grab some information from that object, send it to another class, and finally delete that object from the "Messages" class i originally pulled it from.
My question is do i need to query the entire "Messages" class just to get the first object in it? I don't want to slow down my app due to inefficient code.
Parse.Cloud.afterSave("sendMessage", function(Parse.Message, response) {
var body = null;
var senderName = null;
var senderId = null;
var randUsers = [];
var query = new.Parse.Query(Parse.Message);
query.find({
success: function(results){
body.push(results[1].get("messageBody"));
senderName.push(results[1].get("senderName"));
senderId.push(results[1].get("senderId"));
response.success(getUsers);
},
error: funtion(error){
response.error("Error");
}
});
});
to avoid confusion: "getUsers" is an arbitrary function call.

To retrieve entry from class, you need the query the table. However, your problem is getting the first record which does not require getting the all record. From your code I can see that you get the first record of result array (result[1] ). You can apply the solution; getting the first record of the class that you want to query. You can do it via two ways; either you can set the limit 1 to your query or you can use the first() method. The Parse.Query JS API link is below;
https://parse.com/docs/js/symbols/Parse.Query.html
Check the limit and first methods.
Hope this helps.
Regards.

Related

.remove() is not working on my specific reference

This is my database:
And I want to delete the "small_green" value, so I'm trying with this:
const refToDelete = firebase.database().ref().child('products').orderByChild('fruits').equalTo('small_green');
refToDelete.remove();
But it throws this error:
I'm following this tutorial and this documentation.
What I'm doing wrong?
You can only call remove() on a DatabaseReference, which is a reference to an exact location in the database.
Your firebase.database().ref().child('products').orderByChild('fruits').equalTo('small_green') is a query, which is not a exact location. That means you can't call remove() on it. You will first have to execute the query to get the matching locations, and then call remove() on each of those.
Typically this will be something along the lines of:
const query = firebase.database().ref().child('products').orderByChild('fruits').equalTo('small_green');
query.once('value', functions(snapshot) {
snapshot.forEach(function(childSnapshot) {
childSnapshot.ref.remove();
});
})
Aside from that you're ordering on the wrong child node (as you said in the comments). So you'll want:
const query = firebase.database().ref().child('products/fruits').orderByChild('attrs').equalTo('small_green');

Two-way data binding for a Meteor app

I've built an app that is form-based. I want to enable users to partially fill out a form, and then come back to it at a later date if they can't finish it at the present. I've used iron router to create a unique URL for each form instance, so they can come back to the link. My problem is that Meteor doesn't automatically save the values in the inputs, and the form comes up blank when it is revisited/refreshes. I tried the below solution to store the data in a temporary document in a separate Mongo collection called "NewScreen", and then reference that document every time the template is (re)rendered to auto fill the form. However, I keep getting an error that the element I'm trying to reference is "undefined". The weird thing is that sometimes it works, sometimes it doesn't. I've tried setting a recursive setTimeout function, but on the times it fails, that doesn't work either. Any insight would be greatly appreciated. Or, if I'm going about this all wrong, feel free to suggest a different approach:
Screens = new Meteor.Collection('screens') //where data will ultimately be stored
Forms = new Meteor.Collection('forms') //Meteor pulls form questions from here
NewScreen = new Meteor.Collection('newscreen') //temporary storage collection
Roles = new Meteor.Collection('roles'); //displays list of metadata about screens in a dashboard
//dynamic routing for unique instance of blank form
Router.route('/forms/:_id', {
name: 'BlankForm',
data: function(){
return NewScreen.findOne({_id: this.params._id});
}
});
//onRendered function to pull data from NewScreen collection (this is where I get the error)
Template.BlankForm.onRendered(function(){
var new_screen = NewScreen.findOne({_id: window.location.href.split('/')[window.location.href.split('/').length-1]})
function do_work(){
if(typeof new_screen === 'undefined'){
console.log('waiting...');
Meteor.setTimeout(do_work, 100);
}else{
$('input')[0].value = new_screen.first;
for(i=0;i<new_screen.answers.length;i++){
$('textarea')[i].value = new_screen.answers[i];
}
}
}
do_work();
});
//onChange event that updates the NewScreen document when user updates value of input in the form
'change [id="on-change"]': function(e, tmpl){
var screen_data = [];
var name = $('input')[0].value;
for(i=0; i<$('textarea').length;i++){
screen_data.push($('textarea')[i].value);
}
Session.set("updateNewScreen", this._id);
NewScreen.update(
Session.get("updateNewScreen"),
{$set:
{
answers: screen_data,
first: name
}
});
console.log(screen_data);
}
If you get undefined that could mean findOne() did not find the newscreen with the Id that was passed in from the url. To investigate this, add an extra line like console.log(window.location.href.split('/')[window.location.href.split('/').length-1], JSON.stringify(new_screen));
This will give you both the Id from the url and the new_screen that was found.
I would recommend using Router.current().location.get().path instead of window.location.href since you use IR.
And if you're looking for two way binding in the client, have a look at Viewmodel for Meteor.

Copy a Parse.com class to new class with transformation of values

There is an existing Parse.com class that needs to be copied to a new Parse.com class with some new columns and the transformation of one of the columns. The code currently works and uses the Parse.Query.each method to iterate over all records as detailed in the Parse.com documentation but it stops processing at 831 records although there are 12k+ records in the class. This is odd given each should not have a limit and other default limits are 100 or 1000 for find. Should another method be used to iterate over all records or is there something wrong with the code?
var SourceObject = Parse.Object.extend("Log_Old_Class");
var source_query = new Parse.Query(SourceObject);
var TargetObject = Parse.Object.extend("Log_New_Class")
source_query.each(function(record) {
//save record to new class code works fine
var target_query = new TargetObject();
target_query.set("col1_new",record.col1);
target_query.set("col2_new",record.col2);
//etc...
target_query.save(null, {
success: function(obj) {
//SAVED
},
error: function(obj, error) {
//ERROR
}
});
}).then(function() {
//DONE
},
function(error) {
//error
});
One thing that comes to my mind immediately is that the function is getting timed-out. Parse has time limitations on each function. If I were you, I'd first load all the objects in the source class and then add them separately by having a delay between to API calls (server overload issues can also be present).

Hooks or filters for `Parse.Object`?

Right now I have two sets of data: Post and Images. Every time I fetch a Post I'm having to do a sub-query to grab its image. I'd like to just perform that query to grab the image every time the Post object is initialized. That way every time I have a Post object, I know I also have access to its image. Does this make sense?
Is there any way to do this? The initialize function doesn't give me access to any of the object's data because it's called before it's set.
What you are looking for is the .include() function. It allows you to name a related object via it's field and have it returned with the parent object. Like so:
var Post = Parse.Object.extend("Post");
var query = new Parse.Query(Post);
query.where("author", "Mr. Lebowski");
// Include images associated with the Post
query.include("images");
query.find({
success: function(posts) {
// Images have been retrieved. For example:
for (var i = 0; i < posts.length; i++) {
var Images = i.images; //This will be populated with no sub-query
}
}
});

Parse.com cloud function - manually modify object fields before sending to client

I'm trying to limit the visibility of some fields of parse User object in cloud function.
I have a "Product" class, with a pointer named "owner" to a the "User" that uploaded the item.
I also have a cloud function called "getProducts", I use query.include("owner") to get the owner data at the same time.
What i want to achieve, is that the output of the "getProduct", will be a list of products, but the "Owner" object will contain only certain fields, such as "firstName" or "facebookId",
I don't want to return to the client other sensitive data even though I'm not presenting it (such as Location, email, family name etc..).
After searching I've seen 2 possible solutions.
1.) Cut the User class into 2 classes, 1 of is "Private" class with ACL just for the user.
2.) The second approach that i prefer, i to edit the fields in the cloud function, but i can't seem to change the "owner" object at the "product" object. i'm getting the error:
"Error: Uncaught Tried to save an object with a pointer to a new, unsaved object. (Code: 141, Version: 1.2.19)"
var output[] = [];
_.each(results, function(result) {
var responseData = {};
var owner = result.get("owner");
//Remove fields from the user object
var itemOwnerId = owner.id;
var itemOwnerFirstName = owner.firstName;
var itemOwnerFacebookID = owner.facebookID;
var itemOwner = new Parse.User();
itemOwner.id = itemOwnerId;
itemOwner.id = itemOwnerId;
itemOwner.firstName = itemOwnerFirstName;
itemOwner.facebookID = itemOwnerFacebookID;
result.set("owner", itemOwner);
responseData.item = result;
output.push(responseData);
});
It seems that calling result.set("owner", itemOwner) isn't good, and throwing me exepction:
rror: Uncaught Tried to save an object with a pointer to a new, unsaved object. (Code: 141, Version: 1.2.19)
What am I doing wrong?
The SDK doesn't allow an object that has been changed to be serialized into a response.
A hack way to work around this would be:
result.dirty = function() { return false; };
This would disable the check and allow you to return the modified object.
If you wanted to re-enable it later, you'd need to store the original value of result.dirty and reassign it later.

Categories