I have the following schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ProjectSchema = require('./project.js')
const ClientManagerSchema = new Schema({
name : { type : String, required : true},
project : [ProjectSchema]
});
const ClientManager = mongoose.model('clientManager' , ClientManagerSchema);
module.exports = ClientManager;
Inside the clientmanager schema, there is another as you can see. I want to query the database based on a value inside the ProjectSchema.
I am not sure how to do this but I've tried something like:
const find = () => {
ClientManagers.find({ProjectSchema}).then(e => {
console.log(e);
});
}
however, this gives me an empty array.
Easy-peasy you can refer with dot notation:
const result = await ClientManager.find({ 'project.projectName': 'Foo' })
Related
I am trying to update sub documents with mongoose using the request.body without passing of the sub documents _id. Updating works but mongoose is removing the _id from the sub documents.
Assume the following schemas
// schemas.js
const mongoose = require('mongoose');
const motorSchema = new mongoose.Schema({
type: String,
volume: Number,
});
const carSchema = new mongoose.Schema({
manufacturer: String,
model: String,
motors: [motorSchema],
});
const userSchema = new mongoose.Schema({
username: String,
email: String,
cars: [carSchema]
});
const mongoose = require('mongoose');
// import schemas
const userSchema = require('userSchema');
const carSchema = require('carSchema');
const motorSchema = require('motorSchema');
// create models
const User = mongoose.model("User", userSchema);
const Car = mongoose.model("Car", carSchema);
const Motor = mongoose.model("Motor", motorSchema);
module.exports.updateCar = async function (request, response) {
const condition = {
_id: new mongoose.Types.ObjectId(request.body.userId),
"cars._id": new mongoose.Types.ObjectIt(request.body.carId)
};
// Build object for partial update
const set = {};
for(let field in reqest.body){
set[`cars.$.${field}`] = request.body[field];
}
const update = {
$set = set;
}
User.findOneAndUpdate(condition, update, {new: true, overwrite: false},
(error, user) => {
if(error) {response.send(error)}
response.json(user);
}
}
The problem is that all my _id properties will be overwritten in the motors array. How can I force mongoose as default to not change the _id properties?
If I understand you correctly, the equivalent mongoDB syntax will use arrayFilters, so you can modify your query to use that as well:
For example:
User.findOneAndUpdate(
condition,
{$set: {"cars.$[item].size": "large"}},
{arrayFilters: [{"item._id": new mongoose.Types.ObjectIt(request.body.carId)}]}
)
See how it works on the playground example
According to this method, your code needs the arrayFilters in the options part and the $[<identifier>] in the $set part of the query:
const set = {};
for(let field in reqest.body){
set[`cars.$[item].${field}`] = request.body[field];
}
const update = {
$set = set;
}
User.findOneAndUpdate(
condition,
update,
{
arrayFilters: [{"item._id": new mongoose.Types.ObjectIt(request.body.carId)}],
new: true, overwrite: false
},
(error, user) => {
if(error) {response.send(error)}
response.json(user);
}
I have this code
const usermarket = require('./usermarkets')
const data2 = usermarket.findOne({User:message.author.id})
if(!data2) {
let StonkMarket = new usermarket({
User:message.author.id,
bobloxowned:0,
fattyowned:0,
yeetowned:0,
crunchyrollowned:0,
generatorowned:0,
})
StonkMarket.save().catch(err => console.log(err))
return message.reply('created')
}
But it doesn't create a document in the collection. Here is the usermarket schema code
const userMarket = mongoose.Schema({
User:String,
bobloxowned:Number,
fattyowned:Number,
yeetowned:Number,
crunchyrollowned:Number,
generatorowned:Number,
})
module.exports = mongoose.model("StonkMarketUser", userMarket, 'usermarkets')
It was supposed to create a document with all the things, but instead it did nothing.
const Location = require("../models/locations");
getLocation = async(req, res) => {
await Location.findOne(
{ name: req.query.locationName }, // req.query.locationName is "Gurgaon"
{ restaurantIds: 1 },
(err, location) => {
if (err) throw err;
else {
console.log(location);
/*
{
_id: 6004f9cff6ae9921f89f0f81,
restaurantIds: [ 6004fb53f6ae9921f89f0f83, 600792321b229bae25a66497 ]
}
*/
console.log(location._id); // 6004f9cff6ae9921f89f0f81
console.log(location.restaurantIds); // undefined
return location;
}
}
);
}
module.exports = { getLocation };
Screenshot of the output
This is how the locations collection looks like.
{
"_id" : ObjectId("6004f9cff6ae9921f89f0f81"),
"name" : "Gurgaon",
"restaurantIds" : [
ObjectId("6004fb53f6ae9921f89f0f83"),
ObjectId("600792321b229bae25a66497")
]
}
Here is the locations schema.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const Locations = new Schema({}, { strict: false });
module.exports = mongoose.model("locations", Locations);
I don't know the reason why location.restaurantIds is returning me undefined. Please help me with this. I am new to mongodb.
There will be some reasons might be you have not specified this field in your mongoose schema, try adding field in your schema and you are able to access this field in your query.
Second option if you don't want to specify that field in schema then try lean(),
By default, Mongoose queries return an instance of the Mongoose Document class. Enabling the lean option tells Mongoose to skip instantiating a full Mongoose document and just give you the POJO.
await Location.findOne(.. your query).lean();
restaurantIds is a nested object , you must populate it :
const Location = require("../models/locations");
getLocation = async(req, res) => {
await Location.findOne(
{ name: req.query.locationName },
{ restaurantIds: 1 })
.populate('restaurantIds').then(location => {
console.log(location);
console.log(location._id);
console.log(location.restaurantIds);
return location;
})
.catch(err => {
throw err;
})
);
}
module.exports = { getLocation };
It's look like your restaurantIds is an array, so when you print it, you must use as array. Start by change:
console.log(location.restaurantIds);
to:
console.log(location.restaurantIds[0]);
In this example, you will be printing the first object in the array, and use it in your code as array, it will be OK.
Edit:
After added the restaurantIds, and now we know it's array of ObjectID, and this kind of array cannot be printed.
i tried adding these mongoose plugins mongoose-auto-increment and mongoose-sequence to strapi in config/functions/mongoose.js.. the counter collections are getting created.. but the sequence counts are not getting updated.. Is there a way to get these plugins working or is there a way to implement it myself?
// config/functions/mongoose.js
var autoIncrement = require('mongoose-auto-increment');
module.exports = (mongoose, connection) => {
autoIncrement.initialize(mongoose.connection);
var movieSchema = mongoose.Schema({
title: String
}, { collection : 'Tests' });
movieSchema.plugin(autoIncrement.plugin, { model: 'Test', field: 'movieId', startAt: 1 });
};
In a similar situation I solved it using a new Schema as a Counter for the Ids.
Here is the Counter Schema (models/counter.js):
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CounterSchema = Schema({
_id: {
type: String,
required: true
},
sequence: {
type: Number,
default: 0
}
}, {
collection: 'counters'
});
// export the counter model below and call this method to create the first entry in the counter's table
CounterSchema.statics.createFirstIdForMovie = async () => {
const newCounter = new counter({
_id: "movieid",
sequence: 0
});
newCounter.save();
}
And the Movie Schema would be (models/movie.js):
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const MovieSchema = new Schema({
...,
identifier: {
type: Number,
required: false,
unique: true
},
...
});
MovieSchema.pre('save', async function (next) {
// get the next value for the identifier of 'movieid'
if (this.identifier) {
// just editing, don't need to increment or set a new identifier
return;
}
let c = await counter.findById('movieid');
if (!c) {
c = await counter.createFirstIdForMovie();
}
c.sequence += 1;
await c.save();
this.identifier = c.sequence;
});
Hope it helps!
My workaround was to use a single-type as counter.
Each time I need to use and increment the counter I get the counter single-type and use the built-in createOrUpdate service to get the number.
const counters = await strapi.services.counters.find();
const updatedCounter = await strapi.services.counters.createOrUpdate({
ainumber : counters.ainumber + 1,
});
I know single-types are not ment for this, but it works and is easy to handle.
Hope helps someone
I insert in mongodb with mongoose an array of elements with insertMany function. All goes fine, but I need to take for each element his id. When I insert these elements, i receive an array of docs but i can't iterate them.
Do you have Any solution?
Code example:
const docsExamples = await Examples.insertMany(req.body.examples);
You can use .map() on the array of docs that is returned by insertMany to return a new array of just the ids like this:
#!/usr/bin/env node
'use strict';
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
const Schema = mongoose.Schema;
const schema = new Schema({
name: String
});
const Test = mongoose.model('test', schema);
const tests = [];
for (let i = 0; i < 10; i++) {
tests.push(new Test({ name: `test${i}`}));
}
async function run() {
await mongoose.connection.dropDatabase();
const docs = await Test.insertMany(tests);
const ids = docs.map(d => d.id);
console.log(ids);
return mongoose.connection.close();
}
run();
output:
stack: ./49852063.js
[ '5ad47da0f38fec9807754fd3',
'5ad47da0f38fec9807754fd4',
'5ad47da0f38fec9807754fd5',
'5ad47da0f38fec9807754fd6',
'5ad47da0f38fec9807754fd7',
'5ad47da0f38fec9807754fd8',
'5ad47da0f38fec9807754fd9',
'5ad47da0f38fec9807754fda',
'5ad47da0f38fec9807754fdb',
'5ad47da0f38fec9807754fdc' ]
stack: