Creating relations in parse.com with multiple classes (JavaScript SDK) - javascript

Using parse.com and JavaScript SDK.
I've read alot about this, but cannot find any examples that fit my issue I'm trying to solve.
Here is what I'm attempting to achieve.
I want class "FriendRequest" to have a one to many relation with "myBadges". The child objects held in "myBadges" will be increasing overtime.
The child objects are generated by a function that runs when the user selects a badge and uses "Yes, do it now!" to store it in "myBadges".
At the moment I can only seem to create a relationship within the active class that the function uses. This means I have a relation set up in "myBadges" that just points to the User class, not to the class "FriendRequest".
The relation is in this part of code
success: function(results) {
// The object was saved successfully.
userbadges.relation('BadgeConnect').add(userbadges);
userbadges.save();
So the problem I'm trying to solve is to move the relation link from the "myBadges" class to the "FriendRequest" class???
An example answer how how to achieve this would be great to help me learn the correct approach.
FULL CODE.
<script type="text/javascript">
Parse.initialize("xxxx", "xxxxx");
var MyBadges = Parse.Object.extend("myBadges");
var friendRequest = Parse.Object.extend("FriendRequest");
var userbadges = new MyBadges();
var friendRequest = new friendRequest();
var user = Parse.User.current();
$(document).ready(function() {
$("#send").click(function() {
var badgeselected = $('#badgeselect .go').attr("src");
userbadges.set("BadgeName", badgeselected);
userbadges.set("uploadedBy", user);
//userbadges.set('BadgeName');
//userbadges.save();
userbadges.save(null, {
success: function(results) {
// The object was saved successfully.
userbadges.relation('BadgeConnect').add(userbadges);
userbadges.save();
//location.reload();
},
error: function(contact, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
alert("Error: " + error.code + " " + error.message);
}
});
});
});

Like most problems there are many ways to solve it.
If your goal is to be able to query this relationship from either side then I see two main options:
Create a Cloud Function for after-save of your myBadges class that creates a duplicate of the relation on the FriendRequest side. I'm not sure how much support there is for this as I've never tried it.
Create your own relationship class, e.g. myBadges_FriendRequest, inside it have a pointer to each of the other classes, plus anything else you might want to know about that relationship
Personally I recommend the 2nd option. For querying you can easily request information based on either side of the relationship and use include() to populate both pointers in the result as needed.

Related

Appmaker: How can I get the ID of an item i just created, on client side?

So my latest problem is the following:
I store an id(a foreign key) in a custom property. I want to set the Foreign Key field of an item I just created, to the stored custom property.
I am trying to achieve this in a server script, which looks like this:
function setFKforCustomer(customerID, companyID)
{
var query = app.models.Customer.newQuery();
query.filters.Id._equals(customerID);
var records = query.run();
records[0].Company_fk=companyID;
}
I want to call this function from a client side script, which has to know the customer's ID, the id of the item I just created. I am not entirely sure I am approaching the problem from the right angle, so I am open to other ideas.
Thank you in advance (Markus)!
The question of how to manage relationships in App Maker is probably one of the most asked questions. The official documentation for your specific use case is located here https://developers.google.com/appmaker/models/relations#server_script. The answer would be as follows:
function setFKforCustomer(customerID, companyID)
{
var customerRecord = app.models.Customer.getRecord(customerID);
var companyRecord = app.models.Company.getRecord(companyID);
customerRecord.YourCompanyRelationName = companyRecord; //the field in this case is not Company_fk but whatever the name is of the relation you set up in AM
app.saveRecords([customerRecord]);
}

How to query firebase for many to many relationship?

It is my first time developing a SPA, and I am not using JS frameworks like React, Vue or Angular. My project just uses the firebase sdk and jquery to access the DOM elements.
In my app, the users can be associated with projects. Since that, I have a user-projects and project-users paths to represent that relationship.
When a user logs in my app I request users/uid to get the user data. After that I have to fetch the projects associated with the user. I will take the ids of the associated projects to finally request the data of each project.
I'm trying to use promises as described here, but I get nothing in the console.
function loadUserProjects() {
// Authenticated user
var user = firebase.auth().currentUser;
// General reference to the real time db
var ref = firebase.database().ref();
// Request the user data
ref.child('users/'+user.uid).on('value').then(function(snapshot) {
var user_data = snapshot.val(); console.log(user_data);
// Global variable to store the id of the selected project
project_selected_key = user_data.project_selected;
// Get the list of associated projects
return ref.child('user-projects/'+user.uid).on('value').then(function(snapshot) {
console.log(snapshot);
return snapshot;
});
}).then(function (projectsSnapshot) {
console.log(projectsSnapshot);
// List associated projects
var project_options = '';
projectsSnapshot.forEach(function (e) {
project_options += '<option value="'+e.key+'">'+e.val()+'</option>';
});
if (! project_options) {
project_options = '<option disabled selected value>- NingĂșn proyecto -</option>';
}
$('#project_selected').html(project_options);
}, function(error) {
// Something went wrong.
console.error(error);
});
}
I know that I have to use one additional request, because at this point the <select>will be populated with truevalues (the additional request have to query the full data of each project). But I am not getting messages in the console.
Thanks in advance.
After that, I need to define different levels of privilege in each project, and associate a level when a project is assigned to a specific user. Initially I was very excited about the real time, but it seems that firebase is getting more complicated than I supposed.
A Firebase on() listener can respond to multiple events. A promise can only resolve once, that's why it's only available when you use Firebase's once() operation.
return ref.child('user-projects/'+user.uid).once('value');

Why is my client-side save function firing multiple times?

There are a lot of things going on here, so I'll try to run the line between being brief and being fully descriptive.
Overall goal: I'm creating a barebones (no CSS) admin panel that interfaces with a Parse.com NoSQL/MongoDB database, using HTML forms and Backbone.js to control the communication and save user-inputted information into the Parse database. I am not performing any validation other than some basic stuff client side.
Background: For one specific task, I am doing two things: 1) Grabbing information from Parse.com's database on "page load" (not EXACTLY at page load, but I am not certain how to render the view correctly without doing this - when the user selects the "add purchase" option, the addPurchase View is generated, and I make form submit once with a 0 value to query the database and append the results to the screen - I think this may be causing the issue) and using jQuery to render the information to the HTML page. 2) Then, I am asking the user to select one of 4 options, upon submission of which I will record this as a transaction and generate an entry in a "purchase log" table also with Parse.com.
The problem: The view renders successfully, and the values are successfully retrieved from the database and placed on the page. However, when the user submits the form indicating which option they choose, the resulting transaction record is being stored in the database at a rate of some function of 'n', where n is the number of times a transaction record has already been saved in the current session. If I refresh the view, the 'n' resets. The more times I save without refreshing the page, the more duplicate entries are saved.
I'm new to BackboneJS, Parse.com, and MV* frameworks in general. So I definitely think my code could use some cleanup, and I also feel like I'm missing a key piece of information about how Backbone/HTML forms/Views/the DOM works. So I apologize in advance for any sloppy code; I'm totally cool with any suggestions for cleanup you have as well =P.
My Code: There are a number of places where something could be going wrong, I'll try to keep it succinct.
In the HTML, I have a set of radio buttons that allows the user to decide what action they want to perform. Depending on which button is selection, different forms will render to the browser. Once a form is submitted, Parse attempts to save the values in the database and upon successful save, calls back to the browser with an alert saying save was successful, and then a new AdminPanelView() is called.
The problem of multiple saves happened with other actions too, but I solved the problem by adding the following two lines immediately after the save function:
this.undelegateEvents();
delete this;
However, when I do that inside the query's success block in the addPurchase function, I get a console error telling me that undelegateEvents() is not a function of 'this', and the debugger tells me that 'this' is assigned to the Window at the time this call is made.
If I try to move those same two lines to just after the query function as well, it appears that nothing gets saved at all. The view just immediately switches back to a fresh AdminPanelView, without saving.
The behavior also changes depending on where I put 'return false' statements throughout the addPurchase function, but I haven't been able to figure out exactly what the returns are doing and I've just been playing whack-a-mole with them without really understanding what is happening in the code.
Please help me figure out what I'm doing wrong here! I feel like I'm misunderstanding a core concept here, so I'm eager to find out what it is and learn more about how Backbone and Parse works.
The behavior of the form is governed by some Backbone code:
var AdminPanelView = Parse.View.extend({
events: {
"click form.manageOperations": "manageOperations",
"submit form#newPurchaseInfo": "addPurchase",
//other stuff too
},
el: ".content",
initialize: function(){
this.render();
_.bindAll(this, "manageOperations", "addPurchase");
this.manageOperations();
},
render: function(){
this.$el.html(_.template($("#admin_panel_template").html()))
this.delegateEvents();
},
manageOperations: function()
{
this.$(".inputInfo").hide();
var v = this.$("input[name=defineOperation]:checked").val();
if (v=="add-purchase") { this.$("#newPurchaseInfo").show();
this.$("#newPurchaseInfo").submit();}
else if //cases for the other options - normally I just
call this.$("#new[Whatever]Info.show();
},
addPurchase: function() {
var Perk = Parse.Object.extend("Perk");
var query = new Parse.Query(Perk);
query.find({
success: function(results)
{
var i = 1;
for (var r in results)
{
this.$("#perk"+i+"co").html(results[r].get("company"));
this.$("#perk"+i+"desc").html(results[r].get("description"));
i++;
}
var purchase = Number(this.$("#newPurchaseInfo .perkChoice").val());
// I think this line may be causing the issue.
if (purchase!=0)
{
alert("you indicated you want to use perk # " + purchase +", "
+ "which indicates " + results[purchase-1].get("description")
+ " from " + results[purchase-1].get("company"));
var Purchase = Parse.Object.extend("PurchaseLog");
var purchaseEntry = new Purchase();
user = Parse.User.current();
purchaseEntry.save(
{
info : info,
}, {
success: function(purchase)
{
alert("purchase saved successfully");
new AdminPanelView();
return false;
},
error: function(purchase, error)
{
alert("purchase NOT saved: code " + error.code + ", " + error.message);
}
});
}
return false;
},
error: function(error)
{
alert("error code " + error.code + ": " + error.message);
}
});
// this.undelegateEvents();
// delete this;
return false;
},
Actually, I just figured it out. I love stackoverflow, sometimes just writing the problem description is enough to find the solution! If only I didn't answer my own questions so much, I would have more reputation =P
So, the problem was indeed within my addPurchase function(code highlighted below). What was happening is that the addPurchase view was always instantiated with an initial value of 0 being submitted in order to render the screen. However, as I was doing it defore, the 'this.undelegateEvents()' and 'delete this' were being called on the initial submit regardless. So I was basically deleting the views functionality without fully deleting the view until I tried to submit the form again, at which point I would get an entirely new AdminPanelView() and no save message (the value never saved because the submit value was 0, meaning the save() function was never called).
I simply made it so that the 'this.undelegateEvents()' and 'delete this' methods ONLY get called if the input value is NOT 0. Because in my program logic (however stupid it may be =P), 0 would only be input upon rendering the addPurchase view, in order to render the Perk information to the DOM.
I still feel like my code is convoluted as shit, and I'm open to suggestions on better algorithms, logic, and structure. Part of it is difficult because database return values are only in scope in the success() blocks of the Parse and Backbone functions, so a certain amount of "wall of doom" is hard to avoid.
query.find({
success: function(results)
{
var purchase = Number(this.$("#newPurchaseInfo .perkChoice").val());
if (purchase!=0) {
// attempt to save user in database
purchaseEntry.save(
{
//definition of the object goes here
}, {
success: function(purchase)
{
alert("purchase saved successfully");
new AdminPanelView();
return false;
},
error: function(purchase, error)
{
alert("purchase NOT saved: code " + error.code + ", " + error.message);
}
});
}
return false;
},
error: function(error)
{
alert("error code " + error.code + ": " + error.message);
// return false;
}
});
//This is the solution:
if (Number(this.$("#newPurchaseInfo .perkChoice").val()) != 0)
{
this.undelegateEvents();
delete this;
}
return false;

Parse Inverse Relationship in Javascript (whereEqualTo)

Im using parse with JS and i'm trying to do a reverse relationship...
I have the follow tables..
User
Offers
And the User table has a relationship column to relate a user to an offer and I have two types of relationships used_offers and saved_offers both of which tie the user to a offer.
I decided to put the relationship on the User table instead of the Offers table so that the ACL permission mean that only that user can read the relationship rather than anyone being able to read the relationship on a specific offer.
So... my question is... I am trying to list all the offers but I also want to join (if it exists) a relationship, ie so I know the in data returned it the offer is saved or used.
My current code looks like this...
//Get offer object and create query
var Offer = Parse.Object.extend("Offer");
var offerQuery = new Parse.Query(Offer);
var user = Parse.User.current(); //Get user object//Get user object
console.log(user); //Check user object exists (ie logged in)
offerQuery.whereEqualTo("saved_offers", user); //Get user object//Show relationships
offerQuery.include(["user"]); //Get user object//Return the user data also
offerQuery.find({
success: function(object) {
console.log(object);
},
error: function(error) {
console.log(error);
}
});
I get an error of... uncaught TypeError: undefined is not a function
Which im sure is related to the line...
offerQuery.whereEqualTo("saved_offers", user);
Super appreciate any help here, Parse is great but i cannot find specific documenation to use whereEqualTo (if this is the write command to call) in JS.
Many thanks!
It should be equalTo instead of whereEqualTo.

Simple way to get multiple related objects in Parse.com with Javascript?

I have a Player class. Players can have x number of Trophies. I have the Player objectId and need to get a list of all of their Trophies.
In the Parse.com data browser, the Player object has a column labeled:
trophies Relation<Trophy>
(view Relations)
This seems like it should be so simple but I'm having issues with it.
I have the ParseObject 'player' in memory:
var query = new Parse.Query("Trophy");
query.equalTo("trophies", player);
query.find({
/throws an error- find field has invalid type array.
I've also tried relational Queries:
var relation = new Parse.Relation(player, "trophies");
relation.query().find({
//also throws an error- something about a Substring being required.
This has to be a completely common task, but I can't figure out the proper way to do this.
Anyone know how to do this in Javscript CloudCode?
Many thanks!
EDIT--
I can do relational queries on the user fine:
var user = Parse.User.current();
var relation = user.relation("trophies");
relation.query().find({
I don't understand why this very same bit of code breaks if I'm using a non-user object.
I finally sorted this out, though there is a caveat that makes this work differently than the documentation would indicate.
//Assuming we have 'player', an object of Class 'Player'.
var r = player.relation("trophies");
r.query().find({
success: function(trophies){
response.success(trophies); //list of trophies pointed to by that player's "trophies" column.
},
error: function(error){
response.error(error);
}
})
The caveat: You must have a 'full' player object in memory for this to work. You can't save a player object, grab the object from the success callback and have this work. Some reason, the object that is returned in the success handler is appears to be an incomplete Parse.Object, and is missing some of the methods required to do this.
Another stumbling block about the Parse.com Javascript SDK- A query that finds nothing is still considered successful. So every time you query for something, you must check the length of the response for greater than 0, because the successful query could have returned nothing.
This is what worked for me:
var Comment = Parse.Object.extend("Comment");
var commentsQuery = new Parse.Query(Comment);
commentsQuery.equalTo("parent", video);//for the given 'video' instance, find its children (comments)
commentsQuery.descending("createdAt");
return commentsQuery.find();
Note: of course, video is an instance of the Video class. And returning find() means I'll have to handle the 'promise' in whatever function calls this one.
And here is another function coming from the other angle:
getRecentCommentsOfAllVideos: function(limit) {
var Comment = Parse.Object.extend("Comment");
var commentsQuery = new Parse.Query(Comment);
commentsQuery.descending("createdAt");
commentsQuery.limit(limit);
commentsQuery.include("parent");//this enables the details of the comment's associated video to be available in the result
return commentsQuery.find();
}
(Be sure to read https://parse.com/docs/js_guide and search for the line that says "Include the post data with each comment".)
I also looked at these materials; maybe they'll help you (though they weren't much help for me):
https://parse.com/questions/how-to-retrieve-parent-objects-with-their-children-in-one-call-javascript-api
http://blog.parse.com/2011/12/06/queries-for-relational-data/

Categories

Resources