Mongoose, does this model already exist in the collection - mongodb

I'm using Mongoose on a Node.js server to save data into MongoDB. What I want to do is to check and see if a model object exists in the collection already.
For example heres my model:
var ApiRequest = new Schema({
route: String,
priority: String,
maxResponseAge: String,
status: String,
request: Schema.Types.Mixed,
timestamp: { type: Date, default: Date.now }
});
And here's what I would like to do:
var Request = mongoose.model('api-request', ApiRequest);
function newRequest(req, type) {
return new Request({
'route' : req.route.path,
'priority' : req.body.priority,
'maxResponseAge' : req.body.maxResponseAge,
'request' : getRequestByType(req, type)
});
}
function main(req, type, callback) {
var tempReq = newRequest(req, type);
Request.findOne(tempReq, '', function (err, foundRequest) {
// Bla bla whatever
callback(err, foundRequest);
});
}
The big issues I'm finding are that the tempReq which is a model has an _id variable and a timestamp that is going to be different from what is saved in the database. So I would like to ignore those fields and compare by everything else.
As a note my actual models have more variables than this hence the reason I don't want to use .find({ param : val, ....})..... and instead would like to use the existing model for comparison.
Any ideas? Thanks!

You need to use plain JS objects instead of Mongoose model instances as query objects (the first parameter to find).
So either:
Change newRequest to return a plain object and later pass that into a new Request() call if you need to add it to the database.
OR
In your main function turn tempReq into a query object like this:
var query = tempReq.toObject();
delete query._id;
Request.findOne(query, ...

Related

How to update a nested model in mongoose and mongodb

I'm building a MEAN stack web application.
I have a model in mongoose like this. A model name analyses, where inside , there is a property call points which is another small model name analysis
//model file
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var analysis = new Schema({
ref_id: String,
ele_name: String,
pos_x: Number,
pos_y: Number,
pos_pix_x: Number,
pos_pix_y: Number,
});
var analyses = new Schema({
img_id: String,
store_file_name:String,
points: {
type: [analysis],
default: undefined
},
});
module.exports = mongoose.model('analyses', analyses);
In the database , after I create an entry. there something like this
As you can see, there an id of analyses (5bb...820e) inside have an array of points ( analysis), each has their own id ( 5bb...26d)
Now if I want to update this. I use ExpressJS to define the update API of the server
// API define file
var express = require('express');
var analysesRoutes = express.Router();
// Require Item model in our routes module
var Analyses = require('../models/analyses');
// Defined update route
analysesRoutes.route('/update/:id').put(function (req, res) {
Analyses.findById(req.params.id, function(err, analyses) {
if (!analyses)
return next(new Error('Could not load Document'));
else {
for ( item of Object.keys(req.body)){
analyses[item] = req.body[item];
}
analyses.save().then(analyses => {
res.json({...analyses, status: 200});
})
.catch(err => {
res.status(400).send("unable to update the database");
});
}
});
});
But my problem here is if I want to update only 1 analysis point, I have to send the request to update the big analyses object ( call out id 5bb...820e). Something like this :
//service file
updateAnalyses(newObj, id) {
const uri = 'http://localhost:4000/analyses/update/' + id;
this
.http
.put(uri, newObj)
.subscribe(res => console.log('Done'));
}
// Where newObj here is a big analyses object contains all the unnecessary detail + the point need to be updated
In fact, that point also have an id ( 5bb..26d) itself, is there anyway to update directly to that analysis point ??
Similar question was answered before in Stack overflow.
You can refer to it from here: MongoDB update data in nested field
P.S. There are many answers related to mongodb. Personally the parent.$.child notation worked for me.

Mongoose: Delete Item - First One always gets deleted

I am completely new to the fields of Mongoose and MongoDB.
I am currently trying trying to remove one element from my database.
This is my code so far:
My issueModel:
var mongoose = require('mongoose'); // loading module for mongoose
var db = mongoose.connect('mongodb://localhost/issuedb');
var issueSchema = new mongoose.Schema({
title: String,
description: String,
priority: String,
status: String
});
// Constructor Function:
var issueModel = mongoose.model('issues', issueSchema); // have to give the
name of the collection where the element should be stored + Schema
// Export this Construction Function for this Module:
module.exports = issueModel; // careful: module != model !
My post method for using the delete method:
// creating the router for deleting one item:
router.post('/delete/:id', (req, res) => {
console.log(req.params.id);
issueModel.remove({id: req.params.ObjectId})
.setOptions({ single: true }).exec(function (err, deleted) {})
.then(issues => res.render('issue', {issues: issues}));
The thing i would like to do here is using the object id - which is correctly stored in req.params.ObjectID according to my console.log, and deleting the corresponding object.
But currently , when i have got a table with about 3-4 entries, always the first one gets deleted. Why is that? I am really TOTALLY new and really tried searching a lot, but i could not find any solution until now. I am happy about any tips that would help me.
What am i doing wrong?
The ID in the URL and the Object.ID are the same! Why is the first object deleted then, not the second or the third?
I am hopeless right now.
I also read about the remove() option not being really used in todays time. But we were told at university to use this method right now.
I also tried findOneByID and delete methods i found in the mongoose database.
If you need any more code please let me know!
You can use one of the convenience methods for this: findByIdAndRemove:
issueModel.findByIdAndRemove(req.params.ObjectId, function(err) {
if (err) { ... failed }
});
This will remove a whole document matching the ID which I think its what you want, if you want to a remove property from a document that's a different query.
If you don't use one of the convenience methods which just take IDs (have ById in them), then you have to convert your ID from a string to an ObjectId:
const { ObjectId } = require('mongodb');
issueModel.remove({ id: ObjectId(req.params.ObjectId) }).setOptions({ single: true })

Transform JSON Response Field Name In Mongoose Model

My JSON response contains a field first_name but I want my Mongoose model to represent this field as firstName. Is this possible and if so then how?
You can create a new object with different property names from the one Mongoose returns. A nice way of doing this is to create a transform function. For example, let's say this is your schema:
{
firstName: { type: String, required: true },
lastName: { type: String, required: true }
}
Then you can use this function to create a new object with the desired property names:
function transformDocument (doc) {
return {
first_name: doc.firstName,
last_name: doc.lastName
}
}
Then, when you query the DB, you apply this function to the response:
Person.findOne({ firstName: 'John', lastName: 'Smith' })
.then(transformDocument)
Doug W has a good solution, but if you don't want to be using Promises and chaining .thens, then you can simply add options to the schema like this:
const mongoose = require ('mongoose'); // I am using v5.9.1 at the moment
const { Schema } = mongoose.Schema;
// Specify an options object
const options = {
toJSON: {
versionKey: false
}
// If you ever send the query result as an object,
// you may remove it from there, too, if you wish
// toObject: {
// versionKey: false
// }
};
// Attach the options object to the schema by
// passing it into Schema as the second argument
const mySchema = new Schema({
/** define your schema */
}, options);
This will still save __v to the document in the database. But it will not appear on the json/object when it is the result of a mongoose query.
Besides setting versionKey: false in the options, you may also specify a transform function:
/* ... */
// Specify an options object
const options = {
toJSON: {
// versionKey: false,
transform: function(doc, ret) {
// ret is the object that will be returned as the result
// (and then stringified before being sent)
delete ret.__v;
return ret;
}
}
};
/* ... */
I know this question is nearly two years old, but I needed an answer to this question, and google was not kind to me at the time. I figured it out, and now I'm hoping someone else will be looking for an answer here and find that they have options. Pun not originally intended.

How to find string in array using Mongoose?

I have a schema through mongoose:
const mongoose = require('mongoose');
const recipeSchema = mongoose.Schema({
title: String,
chef: String,
updated: {type: Date, default: Date.now},
region: String,
ingredients: [String],
instructions: [String]
}, { collection: 'recipes' })
module.exports = mongoose.model('Recipes', recipeSchema);
I find the mongoose docs really difficult to understand. I am trying to search for a match of all substring within the 'ingredients' array. I read somewhere that it could be done like so:
.find({ingredients: 'ing1'}) // not working
.find({'ing1': {$in: ingredients}}) // not working
I find it pretty difficult to find in depth tutorials on mongoose as well. Im thinking about not using it at all anymore and just sticking to mongodb shell.
You can use a regex search to match substrings:
.find({ingredients: /ing1/})
The reason that you use mongoose is for testability.
Instead of having to work with a MongoDb instance, which, in Windows can be a pain with the .lock file and the service, mongoose creates the schema that you can test your code with.
The mongoose way is ideal for TDD/TFD.
Below is the model and the mocha test:
recipemodel.js
var mongoose = require('mongoose'),Schema=mongoose.Schema;
var RecipeSchema = new mongoose.Schema({});
RecipeSchema.statics.create = function (params, callback) {
'\\ params is any schema that you pass from the test below
var recipe = new RecipeSchema(params);
recipe.save(function(err, result) {
callback(err, result);
});
return recipe;
};
var recipemodel=mongoose.model('Model', RecipeSchema);
module.exports = recipemodel;
You don't need to describe the schema, mongoose will create it for you when you pass the values of the collection from a mocha test, for example!
The mocha test is below:
var mongooseMock = require('mongoose-mock'),
proxyquire = require('proxyquire'),
chai = require('chai'),
expect = chai.expect,
sinon = require('sinon'),
sinonChai = require("sinon-chai");
chai.use(sinonChai);
describe('Mocksaving a recipe ingredient', function () {
var Recipe;
beforeEach(function () {
Recipe = proxyquire('./recipemodel', {'mongoose': mongooseMock});
});
it('checks if ingredient '+'ing1' + ' saved to mongoose schema', function
(done) {
var callback = sinon.spy();
var recipe = Recipe.create({ title: "faasos", chef:
'faasos',region:'Chennai',ingredients:'ing1',instructions:'abc' },
callback);
expect(recipe.save).calledOnce;
expect(recipe.ingredients).equals('ing341');
done();
});
});
The call to a sinon spy is simply to ensure that the call to the data in the schema got saved (mock saved!) and that the 'save' method did get called at least once. This logic flow is in sync with your actual logic, as you would use in code, when the save on a mongodb collection would be made.
Simply change the value to 'ing1' to make the test pass when you run the test.
For an array type, pass the values as below:
var recipe = Recipe.create({ title: "faasos", chef:
'faasos',region:'Chennai',ingredients:'ing341,ing1',instructions:'abc' }, callback);
expect(recipe.save).calledOnce;
expect(recipe.ingredients).to.include('ing1');
Try this:
.ingredients.find((i) => i === "ing1")
for all elements in the ingredients array, it looks if the content, here a string element, is strictly equal to "ing1"

Is it possible to extract only embedded documents from a Model in Mongoose?

I'd like to run a query on a Model, but only return embedded documents where the query matches. Consider the following...
var EventSchema = new mongoose.Schema({
typ : { type: String },
meta : { type: String }
});
var DaySchema = new mongoose.Schema({
uid: mongoose.Schema.ObjectId,
events: [EventSchema],
dateR: { type: Date, 'default': Date.now }
});
function getem() {
DayModel.find({events.typ : 'magic'}, function(err, days) {
// magic. ideally this would return a list of events rather then days
});
}
That find operation will return a list of DayModel documents. But what I'd really like is a list of EventSchemas alone. Is this possible?
It's not possible to fetch the Event objects directly, but you can restrict which fields your query returns like this:
DayModel.find({events.typ : 'magic'}, ['events'], function(err, days) {
...
});
You will still need to loop through the results to extract the actual embedded fields from the documents returned by the query, however.