What is the preferred way to define an array in mongoose? - node.js

What is the preferred way to define an array in a mongoose Schema ?
Here are the two I found, but I am unable to decide which one is the best to use.
var DocumentSchema = new mongoose.Schema({
wayOne: [
{
type: String
}
],
wayTwo: {
type: [String]
},
});
I would prefer the second way, because I would be able to do something like
wayTwo: {
type: [String],
enum: ['one', 'two', 'three'],
default: []
}
and I don't know how to do this with the first way.
In short, I am looking at some old code I didn't write, and saw the two ways in use, so I was wondering I there was something to note about one of the way, or if it would be safe to standardize in converting all to the best way.

It depends on what sort of data you'll have in the array. The answer is subjective of course, because all of the ways you mention work. Which one is best, however, depends on the kind of data/structure you'll need for your model. Do you know the answer to that yet? Maybe with more specifics we can find a better/focused answer for you, but even then, it's still subjective because they all work.
edit
I would use the first one by the way.

Related

Using Input types for query arguments

Is it a bad practice to use graphql input types for query arguments like its commonly done in mutations, for example
createPost(CreatePostInput!): CreatePostPayload
I see that a lot of api's use separate queries to fetch an entity by different fields, for example
userByEmail(email: String!): User
userByName(name: String!): User
as opposed to
user(email: String, name: String): User
This makes sense, but some queries end up requiring more than one argument, for example paginated results. One might need for example, to modify the start/end cursor, results per page, ordering and others, plus the main query might need more than one argument to find the entities, so these queries end up with 5-6 different arguments.
The question is, why don't people use input types for these?
To the answer below, I can't help but wonder why people deem this
query ($category: String, $perPage: Number, $page: Number, $sortBy: String) {
posts(category: $category, perPage: $perPage, page: $page, sortBy: $sortBy) {
...
}
}
friendlier than this
query( $input: PostQueryInput ) {
posts(input: $input) {
...
}
}
Is it because the input types can only contain primitives? I find this really confusing why its better in one case and worse in another.
I know that people are not forced to to this, you can do it as you like, but in the majority of graphql api's I think it is not done like this and I wonder why might that be - people must have a reason not to do this.

Mongoose query with a list in the model

In my model, I have this field:
…
shows: [{
startAt: Number,
endAt: Number
}],
…
I need a query to select all objects that have a show that hasn't started yet. In other words, I want to find all models that have at least one startAt that is smaller than a given time.
Is this possible? And if so, how can I do it?
As I didn't have any test data, I couldn't test what worked. Now I do, and #joao is absolutely correct.
It seems like Mongoose doesn't care that shows is a list. It was as simple as writing
<model>.find().where('shows.startAt').gt(<constant>).exec(callback);

using _.omit on mongoose User in node.js

I have a mongoose User schema built like this:
var UserSchema = new Schema({
username: { type: String, required: true, index: { unique: true } },
password: { type: String, required: true },
salt: { type: String, required: true}
});
I want to be able to send this user object to the client side of my application but I don't want to sned the password or salt fields.
So I added he following code to my user model module
U
serSchema.methods.forClientSide = function() {
console.log('in UserSchema.methods.forClientSide');
console.log(this);
//var userForClientSide=_.omit(this,'passsword','salt');
var userForClientSide={_id:this._id, username:this.username };
console.log(userForClientSide);
return userForClientSide;
}
I have required the underscore module (its installed locally via a dependency in my package.js).
not the commented out line - I was expecting it to omit the password and salt fields of the user object but it did not do anything :( the logged object had the full set of properties.
when replaced with the currently used like var userForClientSide={_id:this._id, username:this.username }; it gets the results I want but:
1) I want to know why does the _.omit not work.
2) I don't like my current workaround very much because it actually selects some properties instead of omitting the ones I don't like so if I will add any new propertes to the scema I will have to add them here as well.
This is my first attempt at writing something using node.js/express/mongodb/mongoose etc. so It is very possible hat I am missing some other better solution to this issue (possibly some feature of mongoose ) feel free to educate me of the right way to do things like this.
so basically I want to know both what is the right way to do this and why did my way not work.
thanks
1) I want to know why does the _.omit not work.
Mongoose uses defineProperty and some heavy metaprogramming. If you want to use underscore, first call user.toJSON() to get a plain old javascript object that will work better with underscore without all the metaprogramming fanciness, functions, etc.
A better solution is to use mongo/mongoose's fields object and pass the string "-password -salt" and therefore just omit getting these back from mongo at all.
Another approach is to use the mongoose Transform (search for "tranform" on that page). Your use case is the EXACT use case the documentation uses as an example.
You can also make your mongoose queries "lean" by calling .lean() on your query, in which case you will get back plain javascript objects instead of mongoose model instances.
However, after trying each of these things, I'm personally coming to the opinion that there should be a separate collection for Account that has the login details and a User collection, which will make leaking the hashes extremely unlikely even by accident, but any of the above will work.

How do I define Sequelize.STRING length?

I want to define a length of a datatype in sequelize.
There is my source code :
var Profile = sequelize.define('profile', {
public_id: Sequelize.STRING,
label: Sequelize.STRING
})
It create a table profiles with a public_id with a datatype varchar(255).
I would like to define a public_id with varchar(32).
I searched on the doc and the stack but couldn't find any answer...
How can I do that please ?
As it is mentioned in the documentation, use:
Sequelize.STRING(32)
First, I think you need to rethink your design just a little bit. The basic point is that length constraints should be meaningful, not just there to save space. PostgreSQL does not store 'A'::varchar(10) any differently than it does 'A'::text (both are stored as variable length text strings, only as long as the value stored, along with a length specifier and some other metadata), so you should use the longest size that can work for you, and use the lengths for substantive enforcement rather than to save space. When in doubt, don't constrain. When you need to make sure it fits on a mailing label, constrain appropriately.
Secondly Dankohn's answer above:
var Profile = sequelize.define('PublicID', {
public_id: {
validate: { len: [0,32] })
is how you would then add such enforcement to the front-end. Again, such enforcement should be based on what you know you need, not just what seems like a good idea at the time, and while it is generally easier to relax constraints than tighten them, for string length, it's really a no-brainer to do things the other way.
As for using such in other applications, you'd probably want to look up the constraint info in the system catalogs, which gets you into sort of advanced territory.

How dangerous is a mongo query which is fed directly from a URL query string?

I am playing around with node.js, express, and mongoose.
For the sake of getting something up and running right now I am passing the Express query string object directly to a mongoose find function. What I am curious about is how dangerous would this practice be in a live app. I know that a RDBMS would be extremely vulnerable to SQL injection. Aside from the good advice of "sanitize your inputs" how evil is this code:
app.get('/query', function (req, res) {
models.findDocs(req.query, function (err, docs) {
res.send(docs);
});
});
Meaning that a a get request to http://localhost:8080/query?name=ahsteele&status=a would just shove the following into the findDocs function:
{
name: 'ahsteele',
status: 'a'
}
This feels icky for a lot of reasons, but how unsafe is it? What's the best practice for passing query parameters to mongodb? Does express provide any out of the box sanitization?
As far as injection being problem, like with SQL, the risk is significantly lower... albeit theoretically possible via an unknown attack vector.
The data structures and protocol are binary and API driven rather than leveraging escaped values within a domain-specific-language. Basically, you can't just trick the parser into adding a ";db.dropCollection()" at the end.
If it's only used for queries, it's probably fine... but I'd still caution you to use a tiny bit of validation:
Ensure only alphanumeric characters (filter or invalidate nulls and anything else you wouldn't normally accept)
Enforce a max length (like 255 characters) per term
Enforce a max length of the entire query
Strip special parameter names starting with "$", like "$where" & such
Don't allow nested arrays/documents/hashes... only strings & ints
Also, keep in mind, an empty query returns everything. You might want a limit on that return value. :)
Operator injection is a serious problem here and I would recommend you at least encode/escape certain characters, more specifically the $ symbol: http://docs.mongodb.org/manual/faq/developers/#dollar-sign-operator-escaping
If the user is allowed to append a $ symbol to the beginning of strings or elements within your $_GET or $_POST or whatever they will quickly use that to: http://xkcd.com/327/ and you will be a gonner, to say the least.
As far as i know Express doesnt provide any out of box control for sanitization. Either you can write your own Middleware our do some basic checks in your own logic.And as you said the case you mention is a bit risky.
But for ease of use the required types built into Mongoose models at least give you the default sanitizations and some control over what gets into or not.
E.g something like this
var Person = new Schema({
title : { type: String, required: true }
, age : { type: Number, min: 5, max: 20 }
, meta : {
likes : [String]
, birth : { type: Date, default: Date.now }
}
});
Check this for more info also.
http://mongoosejs.com/docs/2.7.x/docs/model-definition.html

Resources