Mongoose Find subdocument in array - mongodb

I have the following data in Robo3t
With this model:
const eleccionSchema = new mongoose.Schema({
e: [{
id: {
type: String,
required: true
},
l:[...]
}],
eleccion: {
type: Number,
required: true,
ref: 'Corte'
}
})
//? Create the model
const Eleccion = mongoose.model('Eleccion', eleccionSchema)
Right now I'm trying to fetch some data based on e.id like this
const eleccion = await Eleccion.findOne({'e.id':'A'})
But it's actually returning the whole array instead of just one

Fixed it with a projection: https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/
const eleccion = await Eleccion.findOne({}, {
'e':
{ $elemMatch: { id: 'A' } }
})

Related

How can I see the products per each category with mongoose

this is my schema for storing products using mongoose as below.
const mongoose = require("mongoose");
const mongoosePaginate = require("mongoose-paginate-v2");
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
},
productImage: {
type: String,
required: true,
},
description: {
type: String,
},
createdAt: {
type: Date,
default: new Date(),
},
deletedAt: {
type: Date,
},
});
productSchema.plugin(mongoosePaginate);
const productModel = mongoose.model("Product", productSchema, "Product");
module.exports = productModel;
and this how I have the schema for storing categories that products are related to
const mongoose = require("mongoose");
const categorySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
product: { type: mongoose.Schema.Types.ObjectId, ref: "Product" },
});
const categoryModel = mongoose.model("Category", categorySchema, "Category");
module.exports = categoryModel;
What I don´t know is how to populate my controller.
getAll: async (req, res) => {
const limitPage = parseInt(req.query.limit, 10) || 10;
const pageChange = parseInt(req.query.page, 10) || 1;
Product.paginate({}, { limit: limitPage, page: pageChange })
.then((result) => {
return res.status(200).json({
message: "GET request to all getAllProducts",
dataCount: result.length,
result: result,
});
})
.catch((err) => {
console.log(err);
res.status(500).json({
error: err,
});
});
},
Please help, I don´t understand why it not being populated and how to see the categories displayed with the categorie they belong to.
You should probably include populate in your query like so:
...
Product.paginate({}, { limit: limitPage, page: pageChange }).populate('category')
...
Note: Are you sure you want to have a 1-1 relation between products and categories. Because this is what you achieve if you set the relation like you did on both schemas. If yes, you should find a way to ensure that this 1-1 relation is enforced each time you save or update objects.

Mongoose delete nested object on time expiration

I'm trying to find out the way to remove nested object in one collection once the document from another collection is expired
LocationsSchema.js
const mongoose = require('mongoose');
const locationsSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'Please add a location name (string)']
},
confirmedBookings: [
{
startDate: {
type: Number
},
finishDate: {
type: Number
}
}]
}, {
timestamps: true
})
module.exports = mongoose.model('Locations', locationsSchema)
BookingsSchema.js
const mongoose = require('mongoose');
const Location = require('./locationModel');
const bookingSchema = mongoose.Schema({
startDate: {
type: Number,
required: [true, 'Please add a valid Date']
},
finishDate: {
type: Number,
> timestamp
required: [true, 'Please add a valid Date'],
index: true
},
location: {
type: mongoose.Schema.Types.ObjectId,
ref: Location
}
}, {
timestamps: true
})
bookingSchema.index({finishDate: 1}, {expireAfterSeconds: 0})
module.exports = mongoose.model('Booking', bookingSchema)
This is how I delete the object manually in
BookingsController.js
const deleteBookings = asyncHandler(async (req, res) => {
const booking = await Booking.findById(req.params.id);
if (!booking) {
res.status(400);
throw new Error('Booking not found');
}
await Location.findOneAndUpdate({_id: booking.location},
{$pull: {'confirmedBookings': {_id: req.params.id}}});
await booking.remove();
res.status(200).json({id: req.params.id});
})
But I also want to be able to delete the objects ones theirs finishDate are before the present time.
I tried to create an TTL index for that but it seems it doesn't work in the way I did it

Recursive mongoose schema does not result in correct object stores

I have a recursive model schema defined in a schema which uses the add() method in the Schema class to incrementally build the schema. It seems to build the paths correctly as shown when I print out the paths. However, when I use the Model defined to store the object in the database, it is missing the inner BNode. Here is a definition of the schema:
import mongoose from 'mongoose';
const BNodeSchema = new mongoose.Schema({
bValue: { type: [Number] },
id: String,
})
const RValue = {
rId: String,
value: Number
}
const ANodeSchema = new mongoose.Schema({
type: {
id: String,
rValues: {
type: Map,
of: RValue
},
}
})
const QuestSchema = new mongoose.Schema({
type: {
_id: { type: String, },
aNode: ANodeSchema,
bNodes: [BNodeSchema],
url: {
type: String
},
id: {
type: String
}
},
},
{ id: false }
)
ANodeSchema.add({ quest: QuestSchema });
const QuestNodeSchema = new mongoose.Schema({
_id: { type: String, unique: true },
quests: { type: [QuestSchema] },
}, {
id: false
})
export const QuestModel = mongoose.model('QuestModel', QuestNodeSchema);
QuestNodeSchema.eachPath(function(path:any) {
console.log(path);
});
{
_id: 12223,
quests:[
{
id: 'Quest-111-111' ,
aNode: {
id: 'A222222',
rValues: {
rId: 'RR1222',
value: 44422
},
quest:{
url: 'https://deptio-opcom',
id: '22222-QST',
bNodes:[{
bValue: 'B22190',
value: 22085
}]
}
}
}
]
}
I have included a sample of the json I am storing in the database. I use a class, not included for brevity to create the equivalent JSON object in the final format to be stored. My feeling is that there is something not quite right with my schema definition. I would be most grateful if someone could help me figure out what I am missing in my definition. Thanks a lot

Moongose returns an empty array when using the .find() method, why?

I have a database in MongoDB with some data, I try to get them with the .find() method, but it returns an empty array instead of the array with the data. Why does this happen and how do I fix it? I'm using ES6
Controller:
import {Game} from '../models/Game.js';
export const getAll = async (req, res) => {
try {
let games = await Game.find();
console.log(games) //returns = []
res.status(200).json(games);
} catch(error) {
console.log('Hubo un error', error)
}
};
Model:
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const GameSchema = new Schema({
name: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
description: {
type: String,
required: true
},
genre: {
type: String,
required: true
},
cover: {
type: String,
required: true
},
platform: {
type: String,
required: true
},
});
export const Game = model("Game", GameSchema);

Does Mongoose Actually Validate the Existence of An Object Id?

I like the validation that comes with Mongoose. We are trying to figure out whether we want to use it, and put up with the overhead. Does anyone know if providing a reference to the parent collection when creating a mongoose schema, (in the child schema, specify the object id of the parent object as a field,) does this then mean that every time you try to save the document it checks the parent collection for the existence of the refereneced object id?
I'm doing it with middleware, performing a search of the element on validation:
ExampleSchema = new mongoose.Schema({
parentId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Example'
}
});
ExampleModel = mongoose.model('Example', ExampleSchema);
ExampleSchema.path('parentId').validate(function (value, respond) {
ExampleModel.findOne({_id: value}, function (err, doc) {
if (err || !doc) {
respond(false);
} else {
respond(true);
}
});
}, 'Example non existent');
I'm using mongoose-id-validator. Works good
var mongoose = require('mongoose');
var idValidator = require('mongoose-id-validator');
var ReferencedModel = new mongoose.Schema({name: String});
var MySchema = new mongoose.Schema({
referencedObj : { type: mongoose.Schema.Types.ObjectId, ref: 'ReferencedModel'},
referencedObjArray: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ReferencedModel' }]
});
MySchema.plugin(idValidator);
No, an ObjectId field that's defined in your schema as a reference to another collection is not checked as existing in the referenced collection on a save. You could do it in Mongoose middleware, if needed.
I found this thread very helpful and this is what I came up with:
This Middleware (I think its one anyway please let me know if not) I wrote checks the referenced model for the id provided in the field.
const mongoose = require('mongoose');
module.exports = (value, respond, modelName) => {
return modelName
.countDocuments({ _id: value })
.exec()
.then(function(count) {
return count > 0;
})
.catch(function(err) {
throw err;
});
};
Example model:
const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const Schema = mongoose.Schema;
const User = require('./User');
const Cart = require('./Cart');
const refIsValid = require('../middleware/refIsValid');
const orderSchema = new Schema({
name: { type: String, default: Date.now, unique: true },
customerRef: { type: Schema.Types.ObjectId, required: true },
cartRef: { type: Schema.Types.ObjectId, ref: 'Cart', required: true },
total: { type: Number, default: 0 },
city: { type: String, required: true },
street: { type: String, required: true },
deliveryDate: { type: Date, required: true },
dateCreated: { type: Date, default: Date.now() },
ccLastDigits: { type: String, required: true },
});
orderSchema.path('customerRef').validate((value, respond) => {
return refIsValid(value, respond, User);
}, 'Invalid customerRef.');
orderSchema.path('cartRef').validate((value, respond) => {
return refIsValid(value, respond, Cart);
}, 'Invalid cartRef.');
orderSchema.path('ccLastDigits').validate(function(field) {
return field && field.length === 4;
}, 'Invalid ccLastDigits: must be 4 characters');
orderSchema.plugin(uniqueValidator);
module.exports = mongoose.model('order', orderSchema);
I'm a very new dev so any feedback is greatly valued!
You can try https://www.npmjs.com/package/lackey-mongoose-ref-validator (I'm the developer)
It also prevents deletion if the reference is used on another document.
var mongooseRefValidator = require('lackey-mongoose-ref-validator');
mongoSchema.plugin(mongooseRefValidator, {
onDeleteRestrict: ['tags']
});
It's an early version, so some bugs are expected. Just fill in a ticket if you find any.
I know this is an old thread but I had the same problem and I came up with a more "modern" solution.
I'm not an expert myself, hope I'm not misleading anyone, but this seems to work:
for example, in a simple "notes" schema, which contains a user field:
const noteSchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: 'User' },
text: String
});
here's the middleware that checks if the userId exists:
noteSchema.path('user').validate(async (value) => {
return await User.findById(value);
}, 'User does not exist');