Parse Cloud Code - Why can't I delete a Parse.Role? - javascript

I can't figure out how to delete a Parse.Role in cloud code. The guide says they are subclasses of Parse.Object and have all the same methods. But I get the following error why I try to delete one:
Object [object Object] has no method 'destroy'
Parse.Cloud.afterDelete("Project", function(request) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.Role);
query.equalTo("name", "hasSound_" + request.object.id);
query.find().then(function(role) {
if(typeof role === 'undefined') {
console.log("role is undefined, cannot delete");
}
else {
role.destroy();
}
}).then(function(success) {
console.log("role deleted: hasSound_" + request.object.id);
}, function(error) {
console.log("error deleting role");
});
});
I had some console.log statements verifying the "name" is correct, so the query should be finding the right object. I'm not sure what else to try.
Also, my roles are named after the ids of Projects. So each Project has a role called "hasSound_[id of project]". When I delete a project, I no longer need the role associated with it. I mean I could leave the unused projects in the database, but that seems wasteful.

find() is fulfilled with an array of matching objects. Since your roles are unique, you can safely change find() to be first(). Or you can keep using find(), but treat the result as an array.

Related

How to check all documents in a collection for a value firestore reactjs

Here is my code:
function loginHandler() {
firestore.collection("users").forEach(user => {
if (user.username === queryUsername && user.password === queryPassword) {
navigate("/");
}
else {
setMode("INCORRECT")
}
})
}
I am trying to check if a doc in the users collection of my firestore db has the username property of the queryUsername and the password property of the queryPassword.
When I run this function:
function loginHandler() {
if (firestore.collection("users").doc("doc that definetly doesnt exist")) {
console.log("exists")
}
else {
console.log("doesnt exist")
}
}
It logs exists for some reason
1. Starting with the second code snippet
firebase.collection("someCollection").doc("some docID which might exist or not")
The code above returns an object or snapshot according to firebase which gives you informations about the document you are looking up whether it exists or not. By code implication your code will always return the document exist since an object passed to an if statement is always true. From firebase official documentation this will be the way to solve this
firebase.collection("SomeCollection").doc("some document ID which exists or not").get()
.then((user)=>{
if(user.exists){
console.log("exists");
} else{
console.log("doesn't exists");
}
})
2. From the First code snippet
SOME NOTES
From the looks of things you want to perform some kind of authentication, though storing users real password is highly risky and a bad practice, if you want to store password you can hash them, but for illustration purpose i will use your code sample.
The first code snippet gets all document from firebase database and do the checking on the client side, this is inefficient and will not be a good practice assuming your collection size goes to infinity, i will attempt to fix your code and then provide a better solution
Your Code Solution
When you read a firebase collection what you get is a snapshots of documents, you have to call .data() on each snapshot to get the actual document stored on firebase. Your code solution will now be like this asuming usernames and passwords are stored raw
function loginHandler() {
firestore.collection("users").get().then(users => {
users.forEach((user)=>{
if (user.data().username === queryUsername && user.data().password === queryPassword) {
navigate("/");
}
else {
setMode("INCORRECT")
}
})
})
}
The Efficient
The most efficient way is to run this codes from database level, in that case you dont have to accumulate costs as your app grows for document reads.
firestore.collection("users").where("username","==",queryUsername)
.where("password","==",querypassword).limit(1).get()
.then((result)=>{
if(result.exists){
console.log("do something after users creds are ok")
}else{
console.log("do something if not ok")
}
})
Note from the answer you have to create a compound index of username and password field in your firestore console check it out here
Not the limit i used is intentional so i can return only one document that matches and call .exists on the snapshot else it will return array of snapshots even if only one document can be found.

Best way to handle non-existent sub-documents in MongoDB query results

I know this question has been asked before in some shape or form but I am looking for the best way to handle query results without a lot of if statements.
Let's say I am looking for a product (sub-document) in a package (document)
Packages.find({_id : req.body.packId, "products._id" : req.body.prodId})
.exec(function(err, result){
if(err) throw err;
// make sure the result array exists and is not empty
if(result && result.length > 0) {
// make sure product array exists and is not empty
if(result.products && result.products.length > 0){
res.json(result);
}
}
});
I noticed I cannot do:
if(result.products.length > 0)
If there is no product, node will crash since it cannot determine 'length' of undefined.
My question is: Is there a better way to do this?
It looks like you are already checking the products_id, so it should never be null if it is returned.
Another way you could do it is by checking that the field is populated in the query.
db.Packages.find({ "products.": { $exists: true, $ne: null } })
You can make the check in the query itself so that you don't have to check in code.

Parse JavaScript returned [object, Object] when retrieving information from parse object

It seems when I am trying to retrieve information from my parse data I am having no issue displaying the information from the user table onto my document but when I try to query another object & insert it into an id element with jQuery using either text();, html();, or val(); I either get nothing or the text becomes into [object Object]. Below is the code I have written down. I also tried a JavaScript method & same output I get [object Object]. Also when I console log JSON stringify query.get("fieldone") I get this.
{"_resolved":false,"_rejected":false,"_resolvedCallbacks":[],"_rejectedCallbacks‌​":[]}
How can I convert it into the string value I want to retrieve. Below is the code
var currentUser = Parse.User.current();
if (currentUser) {
var UserInfo = Parse.Object.extend("UserInfo");
var query = new Parse.Query(UserInfo);
query.equalTo("user", currentUser);
query.find({
success: function(UserInfo) {
// The object was retrieved successfully.
console.log(JSON.stringify(query.get("fieldone")));
document.getElementById('fieldone').innerHTML = query.get("fieldone");
$('#fieldtwo').html(query.get("fieldtwo"));
$('#startDate').html(query.get("startdate"));
$('#endDate').html(query.get("enddate"));
},
error: function(object, error) {
// The object was not retrieved successfully.
// show alert
}
});
}
Your success function is wrong. query.get does a query, just like query.find, it returns a promise (your console.log shows it) and should have a success function too (each of them).
Anyway, the success function receive the object or array of objects you're trying to find/query, try this:
success: function(userFound) {
// The user was retrieved successfully.
console.log(userFound);
}
You should see your user with all his properties.
When you call query.find, you will receive ALL users (in an ARRAY) that match the conditions you set. In this case, it would be just one user.
In this simple example, you could use GET or FIRST, that makes more sense. And you should also use promises (done/fail) instead of callback blocks, because they can be chained and you have improved readability.
And, the final answer, to get the value of a field, you should use GET in the OBJECT, not in the query.
So, my suggestion for your code would be:
var currentUser = Parse.User.current();
if (currentUser) {
var UserInfo = Parse.Object.extend("UserInfo");
var query = new Parse.Query(UserInfo);
query.get(currentUser.id).done(function(userQueried) {
// The object was retrieved successfully.
console.log(JSON.stringify(userQueried));
document.getElementById('fieldone').innerHTML = userQueried.get("fieldone");
$('#fieldtwo').html(userQueried.get("fieldtwo"));
$('#startDate').html(userQueried.get("startdate"));
$('#endDate').html(userQueried.get("enddate"));
}).fail(function(error) {
// The object was not retrieved successfully.
console.log(JSON.stringify(error));
});
}
That's it!

mongodb - capped collections with nodejs

I'm trying to set up and update some capped collections in MongoDB using Node.js (using the native MongoDB driver).
My goal is to, upon running app.js, insert documents into a capped collection, and also to update existing documents in a capped collection. Both of these are running on setInterval(), so every few seconds.
My questions:
I want to create a collection if the collection does not already exist, but if it does I want to insert a document into it instead. What is the correct way to check this?
With capped collections, should I even be explicitly creating them first before inserting anything into them? Normally I believe you can just insert things into a collection without explicitly creating them first, but in this case I need to ensure they are capped. Once the capped collection exists I know how to insert new documents into it, the problem is I need some way to handle the app being used for the first time (on a new server) where the collection doesn't already exist, and I want to do this creation using node and not having to jump into the mongo cli.
The trick here is that the collection needs to be capped, so I can do something like: db.createCollection("collectionName", { capped : true, size : 100000, max : 5000 } ). That will create the capped collection for me, but every time I call it it will call createCollection() instead of updating or inserting - if I call createCollection(), once the collection already exists, will it completely overwrite the existing collection?
An alternative is to turn a collection into a capped one with: db.runCommand({"convertToCapped": "collectionName", size: 100000, max : 5000 });. The problem with this is that node doesn't see runCommand() as a valid function and it errors. Is there something else that I'm meant to be calling to get this to work? It works in the mongo cli but not within node
What type of query do you use to find the first document in a collection? Again, within the mongo cli I can use db.collections.find() with some query, but within node it states that find() is not a valid function
How would I use collection.update() to add some new fields to an existing document? Lets say the document is some simple object like {key1: "value", key2: "value"} but I have an object that contains {key3: "value"}. Key 3 does not exist in the current document, how would I add that to what currently exists? This is somewhat related to #4 above in that I'm not sure what to pass in as the query parameter given that find() doesn't seem to play well with node.
Regarding your questions 1 - 4 about capped collections and creating them automatically, there are several ways to do this. On the one hand, you could run a script to initialise your database so that it has the capped collections available to your client when you run it for the first time. On the other hand, you could have a check to see if there are any documents in the given collection before inserting a document. If there are, you just insert your document and if there aren't, you create the capped collection and then insert the document as a callback to that function. It would work something like this:
var host = "localhost",
port = 27017,
dbName = "so";
var MongoClient = require('mongodb').MongoClient, Server = require('mongodb').Server;
var mongoclient = new MongoClient(new Server(host, port));
var db = mongoclient.db(dbName);
db.open(function(err, db) {
if(err) throw err;
// Capped collection.
var capped = db.collection('capped');
// Document to be inserted.
var document = { "foo": 1, "bar": 1 }
capped.find().count(function(err, count) {
if(err) throw err;
if (count === 0) {
console.log("Creating collection...");
db.createCollection("capped",
{ "capped": true,
"size": 100000,
"max": 5000 },
function(err, collection) {
if(err) throw err;
// Insert a document here.
console.log("Inserting document...");
collection.insert(document, function(err, result) {
if (err) throw err;
});
});
} else {
// Insert your document here without creating collection.
console.log("Inserting document without creating collection...");
capped.insert(document, function(err, result) {
if (err) throw err;
});
}
});
});
Regarding question 5, you can use findOne() to find a document in the collection, though this is not necessarily the first or last. If you want to guarantee the first or last, you can run a find() with a sort() and limit() of 1. Sorting by _id ascending should give you the first document. More information here.
// Sort 1 for ascending, -1 for descending.
capped.find().sort([["_id", 1]]).limit(1).nextObject(function(err, item) {
console.log(item);
});
Finally for question 6, you just use the $set operator with the update() method. More information here.
capped.update({ "foo": 1 }, { "$set": { "bar": 2 } }, {}, function(err, result) {
console.log(result);
});
Note that you can only update documents in place for capped collections, so you cannot do the insert of the extra field you mention. There are other restrictions enumerated here that you might want to be aware of.
[EDIT: Add updating nested fields in last document.]
If you want to update a nested field in the first or last document (use 1 or -1 in the sort, respectively), you can fetch the document, extract the _id, then perform an atomic update on that document. Something like this:
capped.find().sort([["_id", -1]]).limit(1).nextObject(function(err, item) {
if(err) throw err;
capped.update({ "_id": item._id },
{ "$set": { "timeCollected": 15, "publicIP.ip" : "127.0.0.1" }},
function(err, result) {
if(err) throw err;
console.log(result);
});
});
Note that even when updating a field that exists in a document in a capped collection, you need to ensure that the new value fits in the space allocated for the document. So, for example, updating a string value from "1" to "127.0.0.1" will not necessarily work.

Lawnchair.js not updating data

I've got a "LocalStore" object for storing data locally. It's based around a Lawnchair object.
var LocalStore = function(name) {
var that = this;
that.name = name;
that.lawnchair = Lawnchair({ name: that.name }, function(store) {
this.before('save', function(record){
console.log("saving " + that.name);
console.log(record);
});
this.after('save', function(record){
console.log("saved " + that.name);
console.log(record);
that.getData(function(records){
console.log("now it's this");
console.log(records);
});
});
});
that.getData = function(callback) {
that.lawnchair.get(that.name, callback);
};
};
LocalStore is then extended with _.extend(from the Underscore.js library) with this method:
save: function(collection, callback) {
this.lawnchair.save({ key:this.name, value: collection }, function(record) {
callback(record);
});
}
This code is used to update a Backbone.js Collection object to Lawnchair. The first time "save" runs for my Users Collection it saves correctly and shows that the object is a simple key/value pair where value is an Array.
Later in my code when a User selects a Default Project, I modify the Users Collection and call "save" again with an updated "defaultProjectId" on the User. The code runs error free, but the after('save') code for Lawnchair runs and shows me that:
- The record object returned is a key/value pair where value is a full Backbone.js Collection with the defaultProjectId property set correctly.
- The getData method that grabs the latest from the Database still shows as a key/value pair with value a simple Array and defaultProjectId is set incorrectly.
I'm at a loss as what to do. It should just be simply calling "lawnchair.save" updates the record, but it just doesn't do it.
Could you try this jsfiddle?
http://jsfiddle.net/QUgtg/1/
I have recreated your code. Instead of a backbone collection, I am passing in an array of objects. This seems to work. You can see the logging output in Firebug.
I have used my own extend code to add the save(). Though honestly, I don't see why you would want to do it that way, instead of just adding a property to the prototype. Your code may differ in that aspect.
If what I have posted works on your end, could you modify that code to show what are you doing differently? If possible, recreate the issue on jsfiddle...

Categories