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

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.

Related

Check if a key is in gun.js

For example, before I put something in the database I want to check if that entry is already there.
I try to do this:
gun.get('demograph').once((data, key) => {
console.log("realtime updates 1:", data);
});
but I didn't get a response if 'demograph' is or not in the database( for example to get true or false) I just get the result.
I also tried to use .not from extensible API but I is not working.
Anyone has any idea how to check if an entry is already in the database?
I'm not a user of Gun but from what I see in the doc https://gun.eco/docs/API#-a-name-get-a-gun-get-key-
get allows a second argument callback where you can test for not found
gun.get(key, function(ack){
if(ack.err){
server.log(error)
} else
if(!ack.put){
// not found
} else {
// data!
}
})

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.

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

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.

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.

JS Noob: use JavaScript 'for loop' to match a variable to a database

The title explains it pretty well, but I'm trying to build a 'for loop' that matches a variable (in this case, one garnered by an HTML5 form) to a value in a cell in a 2-column database. Then I want to 'console.log' the value in the adjacent (next column over) cell.
Looking for coding help and any suggestions for what type of database would work best with this type of arrangement.
var myDB = {AA:100, BB:50, CC:75, DD:66, EE:40};
function DB(value) {
return myDB[value];
}
console.log(DB('AA'));
It seems to be the best approach for this would be to have a data structure like this:
var myDB = {
'key1' : 'value1'
}
This would remove the need for a "for loop" as you were planning to use which is incredibly inefficient and would enable you to use a simple index check like this:
function getValue( index ) {
if( typeof myDB[index] == 'undefined' ) return false;
return myDB[index];
}
If you need to be able to search on either index, then you'll need to make a slightly more complex database layout (I'm assuming your "database" is actually just javascript data since you wanted to console.log the data.
If you're looking to do this in a server side database and return the data, you'll need AJAX functionality and server side APIs to post those ajax requests to and return your data in JSON. Which is slightly more complicated than what I just suggested above.
Update:
If you wanted to "search" the database values and find the matching key, you would probably have to either run a for loop on the myDB object, or build your database a little differently by having a separate object for each of the keys and one for the data. Something like this:
var myDB = {
'key1' : {
'value1':0,
'value2':1
},
'key2' : {
'value1':0,
'value2':1
},
'data' : {
0:'data_for_record_1',
1:'data_for_record_2'
}
}
Now you can "search" on either of the index columns and get the ID of the data row that corresponds to that matched column. This data structure is very similar to how indexes are used in most databases like MySQL and others. So your "search" function would likely look something like this:
function searchDB( index , value ) {
if( typeof myDB[index][value] == 'undefined' ) return false;
if( typeof myDB.data[myDB[index][value]] == 'undefined' ) return false;
return myDB.data[myDB[index][value]];
}

Categories