Iterate Docs on Mongoose - javascript

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:

Related

Mongoose updating nested subdocuments

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);
}

MongoDb Document Not creating discordjs

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.

Mongoose query for nested schema

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' })

How to implement auto increment for mongodb in strapi?

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

Inconsistency between console.log, Object.keys and Object.getOwnPropertyNames

I am currently using Mongoose, however all these hidden keys are driving me crazy and is disrupting my workflow when these keys are popping up out of nowhere. Here is my code - it's simply logging the docs from the find function:
const mongoose = require('mongoose')
const Kitten = mongoose.model('Kitten', mongoose.Schema({ name: String }));
mongoose.connect('mongodb://localhost/test')
mongoose.connection.on('error', console.log)
mongoose.connection.once('open', function() {
var fluffy = new Kitten({ name: 'fluffy' })
fluffy.save((err, fluffy) => {
if (err) return console.error(err);
Kitten.find({}, (err, docs) => {
for (var i = 0; i < docs.length; ++i) {
const doc = docs[i]
console.log('Object.getOwnPropertyNames ', Object.getOwnPropertyNames(doc))
console.log('Object.keys ', Object.keys(doc))
console.log(doc)
console.log('--')
}
})
})
})
And one of the docs that's logged is
Why are the keys shown by console log in neither .keys nor .getOwnPropertyNames? The console.log output is the one that reflects what's actually in the MongoDB document.
Edit: Edited to use more reasonable code
docs is a list of Mongoose document objects. They don't have fields available for enumeration, there are accessors defined that make them available as doc.fieldName.
There are document toObject and toJSON methods to convert document object to plain object when needed.
The actual problem here is that since document object aren't needed, they shouldn't be queried. Plain objects can be retrieved with lean.
Kitten.find({}).lean().exec((err, docs) => {
for (var i = 0; i < docs.length; ++i) {
const doc = docs[i]
...
}
});
The results you get from "find" are cursers. You need to use "toArray" to load the document to RAM.
const mongoose = require('mongoose')
const Kitten = mongoose.model('Kitten', mongoose.Schema({ name: String }));
mongoose.connect('mongodb://localhost/test')
mongoose.connection.on('error', console.log)
mongoose.connection.once('open', function() {
var fluffy = new Kitten({ name: 'fluffy' })
fluffy.save((err, fluffy) => {
if (err) return console.error(err);
Kitten.find({}).toArray((err, doc) => {
console.log('Object.getOwnPropertyNames ', Object.getOwnPropertyNames(doc))
console.log('Object.keys ', Object.keys(doc))
console.log(doc)
console.log('--')
})
})
})

Categories