I am trying to understand how to query related classes in one call from parse.com using javascript.
I have 2 classes Post and Comment. Post has a column of type relation named 'Comment' and Comment has a column 'parent' of type pointer.
I use the following following code based on parse docs, to save a post and related comment
var Post = Parse.Object.extend("Post");
var Comment = Parse.Object.extend("Comment");
//Create the post
var myPost = new Post();
myPost.set("title", "I'm Hungry");
myPost.set("content", "Where should we go for lunch?");
// Create the comment
var myComment = new Comment();
myComment.set("text", "Let's do subway.");
myComment.set("parent", myPost);
myComment.save();
I am trying to query data like this
var query = new Parse.Query("Post");
query.descending("createdAt");
query.find({
success: function(results) {
for(var i = 0; i < results.length; i++) {
var post = results[i];
var relation = post.relation('Comment');
relation.query().find({
success: function(comments) {
for(var j = 0; j < comments.length; j++) {
console.log(comments[j].get("content"));
}
}
});
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
Can anybody tell me what i am doing wrong here?
The problem in your code is that you're not setting up the relation between the post and the comment. Without that relation setup your query won't work. Here's the working code. Note that I have to save the comments before creating the relation, otherwise you'll get an error from parse.
function createPost() {
var Post = Parse.Object.extend("Post");
var Comment = Parse.Object.extend("Comment");
//Create the post
var myPost = new Post();
myPost.set("title", "I'm Hungry");
myPost.set("content", "Where should we go for lunch?");
// Create the comment
var comment1 = new Comment();
comment1.set("text", "Let's do subway.");
comment1.set("parent", myPost);
var comment2 = new Comment();
comment2.set("text", "Let's do Hoagies.");
comment2.set("parent", myPost);
return Parse.Object.saveAll([comment1, comment2]).then(function() {
// Set the relationship
var relation = myPost.relation('comments');
relation.add(comment1);
relation.add(comment2);
return myPost.save();
});
}
createPost().then(function() {
var query = new Parse.Query("Post");
query.descending("createdAt");
var posts = [];
return query.find().then(function(results) {
var promises = [];
for(var i = 0; i < results.length; i++) {
var post = results[i];
var relation = post.relation('comments');
var postData = { post : post, comments : [] };
posts.push(postData);
console.log("Post : " + post.get('title'));
promises.push(relation.query().find({
success: function(comments) {
for(var j = 0; j < comments.length; j++) {
console.log("Comment " + j + " : " + comments[j].get("text"));
postData.comments.push(comments[j]);
}
}
}));
}
return Parse.Promise.when(promises);
},
function(error) {
alert("Error: " + error.code + " " + error.message);
}
).then(function() {
console.log(posts);
return posts;
});
})
Related
I built this to test reports against csv files containing the data but I am running into this error "Cannot read property 'getText' of undefined" . Please advise thanks. Below is my code
testReport: async function (driver, dataFile) {
var data = await csv({ noheader: true, output: "csv" }).fromFile("./admin/data/" + dataFile);
var trs = await driver.findElements(By.css('.qa-report', 'tbody', 'tr'));
//trs.shift(); // remove first tr - it's the header row
var errors = [];
for (var i in data) {
var row = data[i];
var tds = await trs[i].findElements(By.tagName('td'));
for (var j in row) {
var csvData = data[i][j];
var siteData = await tds[j].getText();
if (siteData != csvData) {
errors.push("[" + i + "," + j + "] - expected(" + csvData + ") got(" + siteData + ")");
}
}
}
if (errors.length > 0) {
errorMessage = "Cells failed to validate:";
for (var i in errors) {
errorMessage += "\n" + errors[i];
}
throw new Error(errorMessage);
}
},
Your iterators looks a bit messed up (as already commented)
try for (var j in tds) { instead of for (var j in row) {
I guess you have more result rows than columns per row. If you still have problems, post the class definitions for findElements or Bywhich we don't know.
I have a Java REST API, with some JSOn data, that I'm working with, in javascript.
I have two methods one to show data, and when to add new data:
so I have added an EventListener to my first bata to submit data:
btn.addEventListener("click", function() {
var request = new XMLHttpRequest();
request.open('GET', 'http://localhost:8084/RestandJson/api/Person');
request.onload = function(){
var data = JSON.parse(request.responseText);
addPerson(data);
};
request.send();
});
with the addPerson method like this:
const addPerson = (data) => {
var fName = document.getElementById("fname").value;
var lName = document.getElementById("lname").value;
var age = document.getElementById("age").value;
var id = data[data.length-1].id +1;
const person = {fName, lName, age, id};
data.push(person);
console.log(person);
for(i = 0; i< data.length; i++){
console.log(data[i]);
}
}
the problem is, that new data is generated for each GET request, so I only want to fetch the data once, and save that in an array, and then add new persons from there on.
I have a method to show the JSON data as well after converting it into objects:
I added an event listener to another button like before where I'm calling this method:
render HTML = (data) => {
let htmlString = "";
for(i = 0; i < data.length; i++){
htmlString += "<p> " + data[i].fName +" " + " " + data[i].lName + " " + data[i].age + " " + data[i].id + "</p>"
}
root.insertAdjacentHTML('beforeend', htmlString);
}
//bind click event on button to add person info
addPersonbtn.addEventListener('click', function() {
addPerson();
});
// fetch all person data from api (call this function when app load)
function getPersonList() {
var request = new XMLHttpRequest();
request.open('GET', 'http://localhost:8084/RestandJson/api/Person');
request.onload = function(){
var data = JSON.parse(request.responseText);
renderHTML(data);
};
request.send();
}
function postPersonData(personInfo) {
// your api to add single persion info
// on success call getPersonList(), it will update the list
}
const addPerson = () => {
var fName = document.getElementById("fname").value;
var lName = document.getElementById("lname").value;
var age = document.getElementById("age").value;
//var id = data[data.length-1].id +1; // handle it on db side, Primary key, auto generation
const person = {fName, lName, age};
postPersonData(person);
}
renderHTML = (data) => {
let htmlString = "";
for(i = 0; i < data.length; i++){
htmlString += "<p> " + data[i].fName +" " + " " + data[i].lName + " " + data[i].age + " " + data[i].id + "</p>"
}
root.insertAdjacentHTML('beforeend', htmlString);
}
i have made pseudo code for you , hope it will helps you a little bit
I have succesfuly stored some geopoints in Parse.com and now in another page i want to console log them all so i can place them into some variables and then put one marker in google map.
So i'm trying with this code to get them but for sure i miss some thing and i need your advice.
Parse.initialize("APPID", "JSKEY");
var PhotoObject = Parse.Object.extend('magazia');
var photoObject = new PhotoObject();
var query = new Parse.Query(PhotoObject);
query.select('latlon');
query.find({
success: function(locationList) {
alert("Successfully retrieved " + locationList.length + " locations.");
for (var i = 0; i < locationList.length; i++) {
var locationsBlock = {};
locationsBlock = JSON.parse(JSON.stringify(locationList[i]));
var location = {};
location = JSON.parse(JSON.stringify(locationsBlock.geolocation));
alert(location.latitude);
};
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
So i have a class called "magazia"
and inside that class there is a column which is called "latlon" and its a Geopoint. The content of this column is for example 48.29124, 28.52015 float number.
The alert shows me the correct number of rows that there are in the "magazia" class.
Does anyone knows why i dont get the results from my code above?
thanks in advance.
Ok that was a stupid mistake
var PhotoObject = Parse.Object.extend('magazia');
var photoObject = new PhotoObject();
var query = new Parse.Query(PhotoObject);
query.select('latlon');
query.find({
success: function(locationList) {
console.log("Successfully retrieved " + locationList.length + " locations.");
for (var i = 0; i < locationList.length; i++) {
var locationsBlock = {};
locationsBlock = JSON.parse(JSON.stringify(locationList[1]));
var location = {};
location = JSON.parse(JSON.stringify(locationsBlock.latlon));
var lat = location.latitude;
var lon = location.longitude;
console.log(lat, lon);
};
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
instead of locationsBlock.geolocation
there should be locationsBlock.latlon
I have a column in my Parse database populated with numbers and I'm trying to add them all together to get a total.
I know how to do the adding together if the data returned is a single array, but I can only figure out how to return the numbers as individual objects. This is my code which does that:
var query = new Parse.Query(Services);
query.exists("costMonthly");
query.find({
success: function (results) {
for (var i = 0; i < results.length; i++) {
var object = results[i];
console.log(object.get('costMonthly'));
}
},
error: function (error) {
alert("Error: " + error.code + " " + error.message);
}
});
How would I go about fetching what I want as an array or at least converting what I have into one?
It looks like you are trying to sum the costMonthly field. You can use reduce to do this easily:
var query = new Parse.Query(Services);
query.exists("costMonthly");
query.find({
success: function (results) {
var sum = results.reduce(function(prev, cur) {
return prev + cur.get('costMonthly');
}, 0);
},
error: function (error) {
alert("Error: " + error.code + " " + error.message);
}
});
If your goal is an array of the costMonthly values, this will work:
var monthlyCosts = results.map(function(item) {
return item.get('costMonthly');
});
Read more about reduce here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
You can create a temporary array , and push results though through iteration , not the best solution , but is very useful if you want to manipulate results later :
var costMonthlyArray=[];
var query = new Parse.Query(Services);
query.exists("costMonthly");
query.find({
success: function (results) {
for (var i = 0; i < results.length; i++) {
var object = results[i];
var cost=object.get('costMonthly');
costMonthlyArray.push(cost);
console.log(cost);
}
},
error: function (error) {
alert("Error: " + error.code + " " + error.message);
}
});
Using parse.com and JavaScript SDK.
This is what I'm attempting to achieve.
A list of users (friends) is returned on the page to the user, They can then click on one of these users and the page is updated to list all of that users items (which are basically images).
This query works correctly and returns a list of users.
var currentUser = Parse.User.current();
var FriendRequest = Parse.Object.extend("FriendRequest");
var query = new Parse.Query(FriendRequest);
query.include('toUser');
query.include('SentTo');
query.include("myBadge");
query.equalTo("fromUser", currentUser);
query.equalTo("status", "Request sent");
query.find({
success: function (results) {
var friends = [];
for (var i = 0; i < results.length; i++) {
friends.push({
imageURL: results[i].get('toUser').get('pic'),
friendRequestId: results[i].id,
username: results[i].get('toUser').get('username')
});
}
// TW: replaced dynamic HTML generation with wrapper DIV that contains IMG and name DIV
_.each(friends, function (item) {
// using a wrapper so the user can click the pic or the name
var wrapper = $('<div class="wrapper" data-friend-request-id="' + item.friendRequestId + '"></div>');
wrapper.append('<img class="images" src="' + item.imageURL + '" />');
wrapper.append('<div>' + item.username + '</div>');
$('#container').append(wrapper);
});
},
error: function (error) {
alert("Error: " + error.code + " " + error.message);
}
});
****This below query should contain the user who has selected above and stored in window.selectedFriendRequestId (which is saved in the variable friendRequest ****
This query looks at the myBadges class and the user reference "SentTo" the ref used is for example a3aePaphBF which is the actual _User objectID.
function FriendProfile() {
var friendRequest = "window.selectedFriendRequestId";
console.log(window.selectedFriendRequestId);
var myBadges = Parse.Object.extend("myBadges");
var query = new Parse.Query(myBadges);
query.equalTo("SentTo", friendRequest);
query.find({
success: function (results) {
// If the query is successful, store each image URL in an array of image URL's
imageURLs = [];
for (var i = 0; i < results.length; i++) {
var object = results[i];
imageURLs.push(object.get('BadgeName'));
}
// If the imageURLs array has items in it, set the src of an IMG element to the first URL in the array
for (var j = 0; j < imageURLs.length; j++) {
$('#imgs').append("<img src='" + imageURLs[j] + "'/>");
}
},
error: function (error) {
// If the query is unsuccessful, report any errors
alert("Error: " + error.code + " " + error.message);
}
});
}
The issue is that the first query is not returning an objectId that I can use in the second query as a reference. For example a3aePaphBF is not returned but cr3LG70vrF is.
How to I return the actual _User objectid in the first query so I can make these match?
To get the ID of a user:
results[i].get('toUser').id
So if you update your section of code that is doing friends.push(...):
friends.push({
imageURL: results[i].get('toUser').get('pic'),
friendRequestId: results[i].id,
username: results[i].get('toUser').get('username'),
userId: results[i].get('toUser').id
});
Then in your bit where you create the wrapper:
_.each(friends, function (item) {
// using a wrapper so the user can click the pic or the name
var wrapper = $('<div class="wrapper"'
+ ' data-friend-request-id="' + item.friendRequestId + '"'
+ ' data-to-user-id="' + item.userId + '"></div>');
wrapper.append('<img class="images" src="' + item.imageURL + '" />');
wrapper.append('<div>' + item.username + '</div>');
$('#container').append(wrapper);
});
Notice that I've added another data-property to hold the ID of the toUser.
Now if you followed the tips from your other question, you can tweak the code that attaches the on-click handler to pass toUserId also:
$('#container').on('click', '.wrapper', function () {
var wrapper = $(this);
var friendRequestId = wrapper.data('friendRequestId');
var toUserId = wrapper.data('toUserId');
FriendProfile(friendRequestId, toUserId);
// other code ...
});
Lastly your FriendProfile() function can now use either of those parameters as needed:
function FriendProfile(friendRequestId, toUserId) {
var toUser = new Parse.User();
toUser.id = toUserId;
var myBadges = Parse.Object.extend("myBadges");
var query = new Parse.Query(myBadges);
query.equalTo("SentTo", toUser);
// ... etc ...
}
NOTE: The User class should be locked down for privacy reasons, you shouldn't be able to read any properties of other users except in Cloud Code when you have the following line in your Cloud Function:
Parse.Cloud.useMasterKey();