Mongoose - solving complex validation that depends on other models - node.js

Isolated data validation is pretty straight forward with something like joi. But what is a good way to solve validation that depends on other models, like given the following collection:
items:
[
{_id: ".....", title: "Product 1", in_stock: 3},
{_id: ".....", title: "Product 2", in_stock: 10},
....
]
And an "order" request like:
{
items:[
{_id: "....", quantity: 3},
{_id: "....", quantity: 6},
...
]
}
Now I want to check that all the items in the order request are in stock (quantity <= in_stock of the corresponding item). What would be good way of solving this?

I myself faced the same problem
The simplest solution is to use mongoose built in validation mechanism so that you don't
need to go ahead and create a lot of schemas in your application
It acctually makes it less robust and the code gets actually prettry hard to maintain as you grow
Joi is recommended when you are using a server db connectivity engine like mongojs
coz it does not have a proper validation mechanism
mongoose on the other hand is a pretty fast and robust mongoDb wrapper that comes with all the possible CRUDs, indexing aggregations and Schema creation.( you can just simply integrate your validations using mongoose validates and make your Schema centered and make your code less redundant
Use mongoose validator property and make a function using regex to check a white list
then throw en error if user input does not meet what u force them

Related

MongoDB update with conditional addToSet/pull

Working in NodeJS with Mongoose, though the methods are all the same.
So I have documents like (simplified):
{_id: 1, message: 'text1'}
{_id: 2, message: 'text2', reactions: [{_id: autoGen1, user: 'bob', reaction:'👍'},
{_id: autoGen2, user: 'bob', reaction:'👎'}
{_id: autoGen3, user: 'meg', reaction:'😵'}]}
I want to run an update query that finds a message and either
Adds the reaction if it doesn't exist
Removes the reaction if it does exist
The user + reaction make a "unique, compound key".
edit
Much testing and experimentation later, I clearly misunderstood how $cond operated and its use-case. Evaluating other options. Open to suggestions.
edit2
Removed my previous, bad attempts. Post was getting too long.
Current Solution: https://mongoplayground.net/p/cgk6qgZ6l9k
Solution based on link in the comments; modified due to array contents.
I really don't like this solution. It's long. It's ugly. Adding an element probably doesn't add the _id. Not an elegant solution overall, in my opinion, unlike the tidy versions linked on SO that deal with primitive arrays and not arrays of objects.
I tried using $elemMatch and $in without success in that playground.

Querying mongoDB using pymongo (completely new to mongo/pymongo)

If this question seems too trivial then please let me know in the comments, I will do further research on how to solve it.
I have a collection called products where I store details of a particular product from different retailers. The schema of a document looks like this -
{
"_id": "uuid of a product",
"created_at": "timestamp",
"offers": [{
"retailer_id": 123,
"product_url": "url - of -a - product.com",
"price": "1"
},
{
"retailer_id": 456,
"product_url": "url - of -a - product.com",
"price": "1"
}
]
}
_id of a product is system generated. Consider a product like 'iPhone X'. This will be a single document with URLs and prices from multiple retailers like Amazon, eBay, etc.
Now if a new URL comes into the system, I need to make a query if this URL already exists in our database. The obvious way to do this is to iterate every offer of every product document and see if the product_url field matches with the input URL. That would require loading up all the documents into the memory and iterate through the offers of every product one by one. Now my question arises -
Is there a simpler method to achieve this? Using pymongo?
Or my database schema needs to be changed since this basic check_if_product_url_exists() is too complex?
MongoDB provides searching within arrays using dot notation.
So your query would be:
db.collection.find({'offers.product_url': 'url - of -a - product.com'})
The same syntax works in MongoDB shell or pymongo.

Is there a way to access mongodb node.js driver functionality while still using mongoose for schema definition?

What I am really trying to do is to make indexes for filtering and string matching of documents based on their property values.
I know that mongodb has built in operators such as $text that are very helpful with this sort of functionality.
I'm not sure how to access these operators while using mongoose, or if there are any methods i need to use to access them.
I want to use mongoose to still define schema and models but need the functionality of native mongodb.
Is this possible?
Below are my views, Please add if I miss anything or if something needs to be modified or well-explained :
1. You will still be able to use mongoDB's native functionalities on using Mongoose models.
2. Mongoose is a kind of wrapper on top of native mongoDB-driver.
3. It would be very useful if you want to have schema based collections/data.
4. Additionally it would provide few more features than native mongoDB's driver. You might see few syntax differences between those two.
5. Few examples like `.findByIdAndUpdate()` & `.populate()` are mongoose specific, which has equivalent functionalities available in mongoDB driver/mongoDB as well.
6. In general it's quiet common to define mongoose models and use those over mongoDB's functionality in coding(As in node.js - You would write all of your same DB queries on Mongoose models, queries that you execute in DB).
Point 2 :
Mongoose is an object document modeling (ODM) layer that sits on top of Node's MongoDB driver. If your coming from SQL, it's similar to an ORM for a relational database.
Point 3 :
In code if you're using mongoose models to implement your write queries, unless you define a field in model - it wouldn't be added to DB though you pass it in request. Additionally you can do multiple things like making a field unique/required etc.. it's kind of making your mongoDB data look like schema based. If your collections data is more like random data(newsfeed kind of thing where fields are not same for each document & you can't predict data) then you might not care of using mongoose.
Point 6 :
Let's say you use mongo shell or a client like mongo compass/robo3T and execute a query that's like this :
db.getCollection('yourCollection').find(
{
$text: {
$search: 'employeeName',
$diacriticSensitive: false
},
country: 'usa'
},
{
employee_id: 1,
name: 1
}
).sort({ score: { $meta: 'textScore' } });
you would do same on mongoose model(As yourCollectionModel is already defined) :
yourCollectionModel.find(
{
$text: {
$search: 'employeeName',
$diacriticSensitive: false
},
country: 'usa'
},
{
employee_id: 1,
name: 1
}
).sort({ score: { $meta: 'textScore' } });
You would see key functionality difference more on writes rather than reads while using mongoose, though all the above is not about performance - If you ask me, I can say you might see much performance gains using mongoose.
Ref : Mongoose Vs MongoDB Driver

How to properly use 'exist' function in mongodb like in sql?

I'm using Node.js + mongodb. I have few documents in my collection and i want to know does my collection have any document matched my condition. Of course i can simply use
myModel.find({ myField: someValue }) and check is anything comes or not. But i want to use solution like sql provides exists keyword? Help me, please
Edit: my bad. I forget to tell that "performance first".
MongoDB's $exists actually doesn't help you very much to find out if a certain document exists in your collection. It is used for example to give you all documents that have a specific field set.
MongoDB has no native support for an sql like exists. What you can use, however, is myModel.findOne({ myField: someValue }) and then check if it is null.
To enhance performance you can tell MongoDB to only load the object id via projection, like this:
myModel.findOne({ myField: someValue }, {_id: 1})
There is an exist mechanism in mongodb, I'll demonstrate a sample below.
For example below, I'm looking for records that have tomato.consensus fields and that it's empty, so I can delete them or avoid them. In case I was looking for "tomato.consensus": Dublin, I'd change Null to Dublin, to match that.
I hope this is helpful, if not fire away any questions
tomato
----consensus
db.movieDetails.updateMany({$and: [
{"tomato.consensus": {$exists: true} },
{"tomato.consensus": null} ] },
]})

Difference between MongoDB and Mongoose

I wanted to use the mongodb database, but I noticed that there are two different databases with either their own website and installation methods: mongodb and mongoose. So I came up asking myself this question: "Which one do I use?".
So in order to answer this question I ask the community if you could explain what are the differences between these two? And if possible pros and cons? Because they really look very similar to me.
I assume you already know that MongoDB is a NoSQL database system which stores data in the form of BSON documents. Your question, however is about the packages for Node.js.
In terms of Node.js, mongodb is the native driver for interacting with a mongodb instance and mongoose is an Object modeling tool for MongoDB.
mongoose is built on top of the mongodb driver to provide programmers with a way to model their data.
EDIT:
I do not want to comment on which is better, as this would make this answer opinionated. However I will list some advantages and disadvantages of using both approaches.
Using mongoose, a user can define the schema for the documents in a particular collection. It provides a lot of convenience in the creation and management of data in MongoDB. On the downside, learning mongoose can take some time, and has some limitations in handling schemas that are quite complex.
However, if your collection schema is unpredictable, or you want a Mongo-shell like experience inside Node.js, then go ahead and use the mongodb driver. It is the simplest to pick up. The downside here is that you will have to write larger amounts of code for validating the data, and the risk of errors is higher.
Mongo is NoSQL Database.
If you don't want to use any ORM for your data models then you can also use native driver mongo.js: https://github.com/mongodb/node-mongodb-native.
Mongoose is one of the orm's who give us functionality to access the mongo data with easily understandable queries.
Mongoose plays as a role of abstraction over your database model.
One more difference I found with respect to both is that it is fairly easy to connect to multiple databases with mongodb native driver while you have to use work arounds in mongoose which still have some drawbacks.
So if you wanna go for a multitenant application, go for mongodb native driver.
From the first answer,
"Using Mongoose, a user can define the schema for the documents in a particular collection. It provides a lot of convenience in the creation and management of data in MongoDB."
You can now also define schema with mongoDB native driver using
##For new collection
db.createCollection("recipes",
validator: { $jsonSchema: {
<<Validation Rules>>
}
}
)
##For existing collection
db.runCommand({
collMod: "recipes",
validator: { $jsonSchema: {
<<Validation Rules>>
}
}
})
##full example
db.createCollection("recipes", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "servings", "ingredients"],
additionalProperties: false,
properties: {
_id: {},
name: {
bsonType: "string",
description: "'name' is required and is a string"
},
servings: {
bsonType: ["int", "double"],
minimum: 0,
description:
"'servings' is required and must be an integer with a minimum of zero."
},
cooking_method: {
enum: [
"broil",
"grill",
"roast",
"bake",
"saute",
"pan-fry",
"deep-fry",
"poach",
"simmer",
"boil",
"steam",
"braise",
"stew"
],
description:
"'cooking_method' is optional but, if used, must be one of the listed options."
},
ingredients: {
bsonType: ["array"],
minItems: 1,
maxItems: 50,
items: {
bsonType: ["object"],
required: ["quantity", "measure", "ingredient"],
additionalProperties: false,
description: "'ingredients' must contain the stated fields.",
properties: {
quantity: {
bsonType: ["int", "double", "decimal"],
description:
"'quantity' is required and is of double or decimal type"
},
measure: {
enum: ["tsp", "Tbsp", "cup", "ounce", "pound", "each"],
description:
"'measure' is required and can only be one of the given enum values"
},
ingredient: {
bsonType: "string",
description: "'ingredient' is required and is a string"
},
format: {
bsonType: "string",
description:
"'format' is an optional field of type string, e.g. chopped or diced"
}
}
}
}
}
}
}
});
Insert collection Example
db.recipes.insertOne({
name: "Chocolate Sponge Cake Filling",
servings: 4,
ingredients: [
{
quantity: 7,
measure: "ounce",
ingredient: "bittersweet chocolate",
format: "chopped"
},
{ quantity: 2, measure: "cup", ingredient: "heavy cream" }
]
});
Mongodb and Mongoose are two different drivers to interact with MongoDB database.
Mongoose : object data modeling (ODM) library that provides a rigorous modeling environment for your data. Used to interact with MongoDB, it makes life easier by providing convenience in managing data.
Mongodb: native driver in Node.js to interact with MongoDB.
mongo-db is likely not a great choice for new developers.
On the other hand mongoose as an ORM (Object Relational Mapping) can be a better choice for the new-bies.
If you are planning to use these components along with your proprietary code then please refer below information.
Mongodb:
It's a database.
This component is governed by the Affero General Public License (AGPL) license.
If you link this component along with your proprietary code then you have to release your entire source code in the public domain, because of it's viral effect like (GPL, LGPL etc)
If you are hosting your application over the cloud, the (2) will apply and also you have to release your installation information to the end users.
Mongoose:
It's an object modeling tool.
This component is governed by the MIT license.
Allowed to use this component along with the proprietary code, without any restrictions.
Shipping your application using any media or host is allowed.
Mongoose is built untop of mongodb driver, the mongodb driver is more low level. Mongoose provides that easy abstraction to easily define a schema and query. But on the perfomance side Mongdb Driver is best.
Mongodb and Mongoose are two completely different things!
Mongodb is the database itself, while Mongoose is an object modeling tool for Mongodb
EDIT: As pointed out MongoDB is the npm package, thanks!
MongoDB is The official MongoDB Node.js driver allows Node.js applications to connect to MongoDB and work with data.
On the other side Mongoose it other library build on top of mongoDB. It is more easier to understand and use. If you are a beginner than mongoose is better for you to work with.

Resources