Not able to update firebase realtime database in angularjs (web) - javascript

This is my code to update a record in firebase.
$scope.EditBrand = function(brand) {
var key = brand.id;
var fredNameRef = firebase.database().ref('all-brands/' + key);
fredNameRef.set(brand, function(error) {
if (error) {
alert ('some error')
} else {
alert ('updated')
}
});
}
I checked the key, and its coming correct.
But when calling this function this is the error.
angular.js:12477Error: Firebase.update failed: First argument contains an invalid key ($$hashKey) in path /$$hashKey. Keys must be non-empty strings and can't contain ".", "#", "$", "/", "[", or "]"
at Error (native)
What is wrong with my code or logic??

According to https://groups.google.com/forum/#!topic/angular/pI0IgNHKjxw, you should create a temporary object to avoid fields generated by angular. So, add this line in your method : var brandObject = angular.fromJson(angular.toJson(brand)); and use brandObject in the rest of the method.

Related

How to update array to firebase?

I am new in this field. I see there are many ways on the internet and most of them is about the old version of Firebase, like using push(), update(), save(). So, I really don't know how to update it. I tried that like this:
function writeNewEvent(eObj) {
// A post entry.
var userObj = authObj.$getAuth();
// Get a key for a new Post.
var newEventKey = ref.child('events').child(userObj.uid).push().key;
// Write the new post's data simultaneously in the posts list and the user's post list.
var updates = {};
updates['/events/' + userObj.uid+ '/' + newEventKey] = userObj;
return ref.update(updates);
}
But the error is:
angular.js:13920 Error: Firebase.update failed: First argument contains an invalid key ($d) in property 'events.LRnkjDgEu1QtuvUTazTwyms4U063.-KW56c87MThrK0PZp-XH.f'. Keys must be non-empty strings and can't contain ".", "#", "$", "/", "[", or "]"
Could you tell me if my method is correct? And how to implement this function.
It looks like you have an ID so you don't need to use push(), just set() at the id like:
// assuming your input looks somthing like:
let eObj = {
"uuid": "98765-8765-1234567890-7890",
"some-data": "stuff",
"other-data": "other stuff",
"numeric-data": 12345
}
function writeNewEventUsingObjUuid(eObj) {
// A post entry.
var userObj = authObj.$getAuth();
return ref.child('events').child(userObj.uid).set(eObj).then(function () {
console.log('Event added with ID: ' + userObj.uid);
}).catch(function (e) {
console.log('Error adding event: ' + e.message);
});
}
If you really want to use push(), firebase will assign you an ID. Note that an empty push() like you had returns a thenable reference. The work is still done asynchronously event though you get an ID upfront.

Subclass of parse.com object in javascript properties after query

I'm using parse.com as the backend to my project and am creating a web page using javascript.
I'm extending PFObject as follow:
var Match = Parse.Object.extend("Match");
On the match object i have a couple properties, let say the first one is "player1"
My question is how can i make it so that when i try to get a property of my match object it succeeds
ie:
var matchQuery = new Parse.Query("Match");
matchQuery.find({
success: function (results) {
_.each(results, function (element, index, list) {
//
var test = element.player1 <<<< here player1 is undefined
})
},
error: function (error) {
alert("Error: " + error.code + " " + error.message);
}
});
Thanks for any tips!
Setting values on the backbone object works like regular JS. The value is retained for as long as the object is in memory, but no longer.
match.memoryOnlyAttribute = "I'll be gone soon";
If match is released and then queried again, memoryOnlyAttribute will be null, as you have observed.
To get a value for a property that persists, it must first be a property on the object. This is typically done in the data browser with the "+ Col" button. (It can also be done in code if your CLP permits).
With that done, the object can only be assigned persistent property values via the set() method...
var Match = Parse.Object.extend("Match");
var match = new Match();
match.set("player1", /* an object here that is of the right type */);
match.save();
Once the object is retrieved, the property in the parse data can be retrieved with the get() method...
matchQuery.first().then(function(matchResult) {
var player1 = match.get("player1");
// player1 will have a value
});

How to query objects in the CloudCode beforeSave?

I'm trying to compare a new object with the original using CloudCode beforeSave function. I need to compare a field sent in the update with the existing value. The problem is that I can't fetch the object correctly. When I run the query I always get the value from the sent object.
UPDATE: I tried a different approach and could get the old register ( the one already saved in parse). But the new one, sent in the request, was overridden by the old one. WHAT?! Another issue is that, even thought the code sent a response.success(), the update wasn't saved.
I believe that I'm missing something pretty obvious here. Or I'm facing a bug or something...
NEW APPROACH
Parse.Cloud.beforeSave('Tasks', function(request, response) {
if ( !request.object.isNew() )
{
var Task = Parse.Object.extend("Tasks");
var newTask = request.object;
var oldTask = new Task();
oldTask.set("objectId", request.object.id);
oldTask.fetch()
.then( function( oldTask )
{
console.log(">>>>>> Old Task: " + oldTask.get("name") + " version: " + oldTask.get("version"));
console.log("<<<<<< New Task: " + newTask.get("name") + " version: " + newTask.get("version"));
response.success();
}, function( error ) {
response.error( error.message );
}
);
}
});
OBJ SENT {"name":"LLL", "version":333}
LOG
I2015-10-02T22:04:07.778Z]v175 before_save triggered for Tasks for user tAQf1nCWuz:
Input: {"original":{"createdAt":"2015-10-02T17:47:34.143Z","name":"GGG","objectId":"VlJdk34b2A","updatedAt":"2015-10-02T21:57:37.765Z","version":111},"update":{"name":"LLL","version":333}}
Result: Update changed to {}
I2015-10-02T22:04:07.969Z]>>>>>> Old Task: GGG version: 111
I2015-10-02T22:04:07.970Z]<<<<<< New Task: GGG version: 111
NOTE: I'm testing the login via cURL and in the parse console.
CloudCode beforeSave
Parse.Cloud.beforeSave("Tasks", function( request, response) {
var query = new Parse.Query("Tasks");
query.get(request.object.id)
.then(function (oldObj) {
console.log("-------- OLD Task: " + oldObj.get("name") + " v: " + oldObj.get("version"));
console.log("-------- NEW Task: " + request.object.get("name") + " v: " + request.object.get("version"));
}).then(function () {
response.success();
}, function ( error) {
response.error(error.message);
}
);
});
cURL request
curl -X PUT \
-H "Content-Type: application/json" \
-H "X-Parse-Application-Id: xxxxx" \
-H "X-Parse-REST-API-Key: xxxxx" \
-H "X-Parse-Session-Token: xxxx" \
-d "{\"name\":\"NEW_VALUE\", \"version\":9999}" \
https://api.parse.com/1/classes/Tasks/VlJdk34b2A
JSON Response
"updatedAt": "2015-10-02T19:45:47.104Z"
LOG
The log prints the original and the new value, but I don't know how to access it either.
I2015-10-02T19:57:08.603Z]v160 before_save triggered for Tasks for user tAQf1nCWuz:
Input: {"original":{"createdAt":"2015-10-02T17:47:34.143Z","name":"OLD_VALUE","objectId":"VlJdk34b2A","updatedAt":"2015-10-02T19:45:47.104Z","version":0},"update":{"name":"NEW_VALUE","version":9999}}
Result: Update changed to {"name":"NEW_VALUE","version":9999}
I2015-10-02T19:57:08.901Z]-------- OLD Task: NEW_VALUE v: 9999
I2015-10-02T19:57:08.902Z]-------- NEW Task: NEW_VALUE v: 9999
After a lot test and error I could figure out what was going on.
Turn out that Parse is merging any objects with the same class and id into one instance. That was the reason why I always had either the object registered in DB or the one sent by the user. I honestly can't make sense of such behavior, but anyway...
The Parse javascript sdk offers an method called Parse.Object.disableSingeInstance link that disables this "feature". But, once the method is called, all object already defined are undefined. That includes the sent object. Witch means that you can't neither save the sent object for a later reference.
The only option was to save the key and values of the sent obj and recreate it later. So, I needed to capture the request before calling disableSingleInstance, transform it in a JSON, then disable single instance, fetch the object saved in DB and recreate the sent object using the JSON saved.
Its not pretty and definitely isn't the most efficient code, but I couldn't find any other way. If someone out there have another approach, by all means tell me.
Parse.Cloud.beforeSave('Tasks', function(request, response) {
if ( !request.object.isNew() ) {
var id = request.object.id;
var jsonReq;
var Task = Parse.Object.extend("Tasks");
var newTask = new Task;
var oldTask = new Task;
// getting new Obj
var queryNewTask = new Parse.Query(Task);
queryNewTask.get(id)
.then(function (result) {
newTask = result;
// Saving values as a JSON to later reference
jsonReq = result.toJSON();
// Disable the merge of obj w/same class and id
// It will also undefine all Parse objects,
// including the one sent in the request
Parse.Object.disableSingleInstance();
// getting object saved in DB
oldTask.set("objectId", id);
return oldTask.fetch();
}).then(function (result) {
oldTask = result;
// Recreating new Task sent
for ( key in jsonReq ) {
newTask.set( key, jsonReq[key]);
}
// Do your job here
}, function (error) {
response.error( error.message );
}
);
}
});
If I were you, I would pass in the old value as a parameter to the cloud function so that you can access it under request.params.(name of parameter). I don't believe that there is another way to get the old value. An old SO question said that you can use .get(), but you're claiming that that is not working. Unless you actually already had 9999 in the version...
edit - I guess beforeSave isn't called like a normal function... so create an "update version" function that passes in the current Task and the version you're trying to update to, perhaps?
Rather than performing a query, you can see the modified attributes by checking which keys are dirty, meaning they have been changed but not saved yet.
The JS SDK includes dirtyKeys(), which returns the keys that have been changed. Try this out.
var attributes = request.object.attributes;
var changedAttributes = new Array();
for(var attribute in attributes) {
if(object.dirty(attribute)) {
changedAttributes.push(attribute);
// object.get(attribute) is changed and the key is pushed to the array
}
}
For clarification, to get the original attribute's value, you will have to call get() to load those pre-save values. It should be noted that this will count as another API request.
Hey this worked perfectly for me :
var dirtyKeys = request.object.dirtyKeys();
var query = new Parse.Query("Question");
var clonedData = null;
query.equalTo("objectId", request.object.id);
query.find().then(function(data){
var clonedPatch = request.object.toJSON();
clonedData = data[0];
clonedData = clonedData.toJSON();
console.log("this is the data : ", clonedData, clonedPatch, dirtyKeys);
response.success();
}).then(null, function(err){
console.log("the error is : ", err);
});
For those coming to this thread in 2021-ish, if you have the server data loaded in the client SDK before you save, you can resolve this issue by passing that server data from the client SDK in the context option of the save() function and then use it in the beforeSave afterSave cloud functions.
// eg JS client sdk
const options = {
context: {
before: doc._getServerData() // object data, as loaded
}
}
doc.save(null, options)
// #beforeSave cloud fn
Parse.Cloud.beforeSave(className, async (request) => {
const { before } = request.context
// ... do something with before ...
})
Caveat: this wouldn't help you if you didn't have the attributes loaded in the _getServerData() function in the client
Second Caveat: parse will not handle (un)serialization for you in your cloud function, eg:
{
before: { // < posted as context
status: {
is: 'atRisk',
comment: 'Its all good now!',
at: '2021-04-09T15:39:04.907Z', // string
by: [Object] // pojo
}
},
after: {
status: { // < posted as doc's save data
is: 'atRisk',
comment: 'Its all good now!',
at: 2021-04-09T15:39:04.907Z, // instanceOf Date
by: [ParseUser] // instanceOf ParseUser
}
}
}

Delete specific object from Parse.com

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. Below is my code, however it doesn't work. How should i rework this?
Should i use a different approach than the "destroy" method such as collection.remove?
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"));
results[1].destroy({
success: function(results[1]){
//the first object in the class "Messages" was deleted
}, error: function(results[1], error){
//the first object was not deleted
}
});
response.success(getUsers);
}, error: funtion(error){
response.error("Error");
}
});
});
to avoid confusion: "getUsers" is an arbitrary function call.
Duplicate question with the entry;
Query entire class vs first object in the class
However, if you want to delete a specific object you need something which uniquely identify the
object. Then, one way is using the Parse object id to delete the object from class.
To delete the object via cloud, you need to use the destroy method of ParseObject. But if you have multiple objects then you can use destroyAll method. One example of ParseObject delete method on javascript API is below;
var yourClass = Parse.Object.extend("YourClass");
var query = new Parse.Query(yourClass);
query.get("yourObjectId", {
success: function(yourObj) {
// The object was retrieved successfully.
yourObj.destroy({});
},
error: function(object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and description.
}
});
Hope this helps,
Regards.
Some changes into above :
var missingDataQuery = new Parse.Query(missingDataObj)
missingDataQuery.equalTo('projectId',project);
var getMissingData = missingDataQuery.find({
success: function(yourObj) {
console.log('here')
yourObj[0].destroy({})
},
error: function(object, error) {
}
});
Here we getting object and then destroying it.
func deleteImage(imageId: String) {
let query = PFQuery(className: "ClassName")
query.whereKey("imageId", equalTo: "\(imageId)")
query.findObjectsInBackground {
(objects:[PFObject]?, error: Error?) -> Void in
if error == nil && (objects != nil) {
for object in objects! {
object.deleteInBackground()
print("object deleted")
}
}
}
}

Call a Stored Procedure in HANA

I am trying to call a stored procedure in java from my .xsjs file. The procedure gets 2 input parameters and returns one. I can call it from an SQL console without any problem by writing:
call "MYSCHEMA"."MyPackage.procedures::addUserC50" ('name', 'lastname', ?)
This is the code in my .xsjs file, I think that it fails in the prepareCall statement. I have tried different combinations (with and without double quotation marks, with and without the name of the schema/package, with and without "(?,?,?)", with and without "{ }".... But nothing works, I always get the 500 Internal server error when I try to execute it.
Does anybody know where the error is or what is the exact syntax for the prepareCall method?
var output = 0,
query = "";
var conn;
var cstmt;
try {
conn = $.db.getConnection();
query = "{ call \"MYSCHEMA\".\"MyPackage.procedures/addUserC50\"(?,?,?) }";
cstmt = conn.prepareCall(query); // <-- Fails
cstmt.setString(1, userName);
cstmt.setString(2, userLastname);
cstmt.execute();
output = cstmt.getInteger(3);
conn.commit();
$.response.status = $.net.http.OK;
$.response.setBody("Successfully created: " + output);
}
catch (e) {
$.response.status = $.net.http.BAD_REQUEST;
$.response.setBody("0");
}
finally {
if (cstmt !== null)
cstmt.close();
if (conn !== null)
conn.close();
}
This is the error that gives back: InternalError: dberror(Connection.prepareCall): 328 - invalid name of function or procedure: MyPackage.procedures/addUserC50: line 1 col 18 (at pos 17) at ptime/query/checker/check_call.cc:21
According to this documentation, it should be something like
var myCallableStatement = myconnection.prepareCall("{call myprocedure(?)}");
Thank you
I managed to make it run, this is the syntax that worked:
query = "call \"MyPackage.procedures::addUserC50\"(?, ?, ?)";
Thank you for your help #shofmn
There could be different reasons why the call is failing. You can investigate your error much easier if you return the error message in the HTTP response. You can do this easily:
try {
// Your code execution here
}
catch (e) {
$.response.contentType = "text/html";
$.response.setBody(e.name + ": " + e.message));
}
If the error message doesn't help you solving the problem, paste the error message in here so that it is more easy for us to investigate as well.

Categories

Resources