Why can't I rename the collection using the Schema? - javascript

I want to rename the collection in my schema, but mongodb keeps using the old name.
I have been running my code with the schema name set to '__filters', but now I need to change the name to '__filter'. ( NOT plural )
When I create a filter, mongodb creates a '__filters' collection
This is how I had the original Schema set up, note plural 'filters'
// create the schema
const FiltersSchema = new Schema({
test: {type: String, required: true},
})
module.exports = Filters = mongoose.model('__filters', FiltersSchema)
Now I want to make the name of the collection singular '__filter'. This is the new schema that I want to use: NOTE: ALL singular now
// create the schema
const FilterSchema = new Schema({
test: {type: String, required: true},
})
module.exports = Filter = mongoose.model('__filter', FilterSchema)
Here is the code that I am using:
const Filter = require('./Filter');
createFilter = ( test ) => {
return new Promise((resolve, reject) =>{
var errors = {};
Filter.findOne( {test:test} )
.then(found => {
if(found) {
errors.err = {'inUse':'already created'};
console.log(errors);
reject(errors);
} else {
const newFilter = new Filter({
test: test
});
newFilter.save()
.then(f => {
if(debugThis){
console.log(' ');
console.log(' created ' + JSON.stringify(f));
console.log(' ');
}
resolve(f);
})
.catch(err => {
errors.exception = {'save':err};
console.log(errors);
reject(errors);
});
}
})
.catch(err => {
errors.exception = {'findOne':err};
reject(errors);
})
});
};
it's almost like there is some cache somewhere that is keeping the older 'filters' schema around.
Is there something I need to clear?
I have even tried this, which didn't work either
let dbc = mongoose.connection.db;
dbc.collection('filters').rename('filter')
.then()
.catch(err =>{});
I closed DevStudio and restarted it.
I have created a new database in MongoDB
I restarted the MongoDB server service
Nothing seems to reset '__filters' to '__filter'
In desperation, I remove the _filter from the schema and it crashed and spit this out:
TypeError: Cannot read property 'toLowerCase' of undefined
at pluralize
(\node_modules\mongoose-legacy-pluralize\index.js:85:13)
Does mongoose make names plural automatically ??
Well blow me down olive oil... mongoose makes stuff plural... how 'nice' of them to do that... I DON'T want plural names...

OMG... I can't believe this... 4 hours of my time wasted on this stupid stuff:
Why does mongoose always add an s to the end of my collection name

Related

Model.create() from Mongoose doesn´t save the Documents in my Collection

I have created a sigle app with a Schema and a Model to create a Collection and insert some Documents.
I have my todoModel.js file:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const todoSchema = new Schema({
username: String,
todo: String,
isDone: Boolean,
hasAttachment: Boolean
});
const Todos = mongoose.model("Todo", todoSchema);
module.exports = Todos;
Then I have created a setUpController.js file with a sample of my Documents. Then I create a Model and I pass my sample of Documents and my Schema. I create a response to send tje result in JSON.
Everything good here, as I get the result in json when accessing to the route.
Here is the code:
Todos.create(sampleTodos, (err, results) => {
if (!err) {
console.log("setupTodos sample CREATED!")
res.send(results);
}
else {
console.log(`Could not create the setupTodos Database sample, err: ${err}`);
}
});
My problem is that this Documents don´t get saved in the collection !! When I access to the database, nothing is there.
This is my app.js file:
mongoose.connect("mongodb://localhost:27017/nodeTodo")
.then(connection => {
app.listen(port);
})
.catch(err => {
console.log(`Could not establish Connection with err: ${err}`);
});
Could anyone help me please ?
Thank you
Try creating an instance and making the respective function call of that instance. In your case, save the document after creating an instance and it works like a charm.
const newTodos = new Todos({
username: "username",
todo: "todos",
isDone: false,
hasAttachment: flase
});
const createdTodo = newTodos.save((err, todo) => {
if(err) {
throw(err);
}
else {
//do your staff
}
})
after the collection is created you can use the function inserMany to insert also a single document the function receives an array of objects and automatically saves it to the given collection
example:
Pet = new mongoose.model("pet",schemas.petSchema)
Pet.insetMany([
{
//your document
}])
it will save only one hardcoded document
I hope it was helpful

Mongoose populate returns empty array or list of ObjectIds

I am practicing my express.js skills by building a relational API and am struggling to populate keys in a schema.
I am building it so I have a list of properties, and those properties have units. The units have a propertyId key.
This is currently returning an empty array, whereas if i remove the populate({}) it returns an array of ObjectIds.
I've read a number of posts and some people solved this by using .populate({path: 'path', model: Model}); but this doesn't seem to be doing the trick. I think it might be the way I am adding a propertyId to the unit but I'm not sure. Can anyone see where I am going wrong? Any help will be massively appreciated.
Here are the schemas.
Property:
const mongoose = require('mongoose');
const { Schema } = mongoose;
const PropertySchema = new Schema({
title: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
units: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'unit'
}
]
});
module.exports = Property = mongoose.model('property', PropertySchema);
Unit:
const mongoose = require('mongoose');
const { Schema } = mongoose;
const UnitSchema = new Schema({
title: {
type: String,
required: true
},
propertyId: {
type: Schema.Types.ObjectId,
ref: 'property'
}
});
module.exports = Unit = mongoose.model('unit', UnitSchema);
I am then creating the unit like this:
-- api/properties/:id/units --
router.post('/:id/units', async (req, res) => {
// Get fields from req.body
const { title } = req.body;
// Get current property
const property = await Property.findById(req.params.id);
try {
// Throw error if no property
if (!property) {
return res.status(400).json({ msg: 'Property not found' });
}
// Create new unit
const newUnit = new Unit({
title,
propertyId: req.params.id
});
// Add new unit to property's units array
property.units.unshift(newUnit);
// Save property
await property.save();
// Return successful response
return res.status(200).json(property);
} catch (error) {
console.error(error.message);
return res.status(500).send('Server error');
}
});
And trying to populate in the GET request
-- /api/properties/:id/units --
const Unit = require('../../models/Unit');
router.get('/:id/units', async (req, res) => {
const property = await Property.findOne({ _id: req.params.id }).populate({path: 'units', model: Unit});
const propertyUnits = property.units;
return res.status(200).json(propertyUnits);
});
If i remove the .populate({path: 'units', model: Unit});, I get a list of unit id's like this:
[
"5ff7256cda2f5bfc1d2b9108",
"5ff72507acf9b6fb89f0fa4e",
"5ff724e41393c7fb5a667dc8",
"5ff721f35c73daf6d0cb5eff",
"5ff721eb5c73daf6d0cb5efe",
"5ff7215332d302f5ffa67413"
]
I don't know, why you don't try it like this:
await Property.findOne({ _id: req.params.id }).populate('units')
I've been try that code above and it's working.
Note: Make sure to check your req.params.id is not null or undefined and make sure the data you find is not empty in your mongodb.
Updated: I've been try your code and it's working fine.
The issue was caused by inconsistent naming and not saving the new created unit as well as the updated property.
I double checked all my schema exports and references and noticed I was using UpperCase in some instances and LowerCase in others, and saved the newUnit as well as the updated property in the POST request and it worked.

How to use dataloader?

Im trying to figure this out.
I want to get all my users from my database, cache them
and then when making a new request I want to get those that Ive cached + new ones that have been created.
So far:
const batchUsers = async ({ user }) => {
const users = await user.findAll({});
return users;
};
const apolloServer = new ApolloServer({
schema,
playground: true,
context: {
userLoader: new DataLoader(() => batchUsers(db)),// not sending keys since Im after all users
},
});
my resolver:
users: async (obj, args, context, info) => {
return context.userLoader.load();
}
load method requiers a parameter but in this case I dont want to have a specific user I want all of them.
I dont understand how to implement this can someone please explain.
If you're trying to just load all records, then there's not much of a point in utilizing DataLoader to begin in. The purpose behind DataLoader is to batch multiple calls like load(7) and load(22) into a single call that's then executed against your data source. If you need to get all users, then you should just call user.findAll directly.
Also, if you do end up using DataLoader, make sure you pass in a function, not an object as your context. The function will be ran on each request, which will ensure you're using a fresh instance of DataLoader instead of one with a stale cache.
context: () => ({
userLoader: new DataLoader(async (ids) => {
const users = await User.findAll({
where: { id: ids }
})
// Note that we need to map over the original ids instead of
// just returning the results of User.findAll because the
// length of the returned array needs to match the length of the ids
return ids.map(id => users.find(user => user.id === id) || null)
}),
}),
Note that you could also return an instance of an error instead of null inside the array if you want load to reject.
Took me a while but I got this working:
const batchUsers = async (keys, { user }) => {
const users = await user.findAll({
raw: true,
where: {
Id: {
// #ts-ignore
// eslint-disable-next-line no-undef
[op.in]: keys,
},
},
});
const gs = _.groupBy(users, 'Id');
return keys.map(k => gs[k] || []);
};
const apolloServer = new ApolloServer({
schema,
playground: true,
context: () => ({
userLoader: new DataLoader(keys => batchUsers(keys, db)),
}),
});
resolver:
user: {
myUsers: ({ Id }, args, { userLoader }) => {
return userLoader.load(Id);
},
},
playground:
{users
{Id
myUsers
{Id}}
}
playground explained:
users basically fetches all users and then myusers does the same thing by inhereting the id from the first call.
I think I choose a horrible example here since I did not see any gains in performence by this. I did see however that the query turned into:
SELECT ... FROM User WhERE ID IN(...)

MongoDB schema does not insert property when using with insertOne function

The initial problem was solved, thanks!
Now, whenever I insert the document it comes out like this:
{
_id: "5e3b64b6655fc51454548421",
todos: [ ],
title: "title"
}
It should look like this since in the schema the "title" property is above the "todos" property.
{
_id: "5e3b64b6655fc51454548421",
title: "title",
todos: [ ]
}
JavaScript
//project schema
const schema = mongoose.Schema({
title: String,
todos: []
});
const Project = mongoose.model('Project', schema);
//add a project
app.post('/addProject', (req, res) => {
const collection = db.collection('projects')
const proj = new Project({title: req.body.title});
collection.insertOne(proj, function(err, results) {
if (err){
console.log(err);
res.send('');
return
}
res.send(results.ops[0]) //retruns the new document
})
})
You're renaming your key in below line:
const proj = new Project({title: req.body.projTitle});
Your schema expects projTitle, try to change it to:
const proj = new Project({projTitle: req.body.projTitle});
Mongoose schema defines the structure of your document. Whenever you try to save additional field that's not defined in your schema it will be simply ignored by mongoose.
You are entering wrong key while creating new Project object. Change it to the correct key as per your schema and you'll be good to go.
//project schema
const schema = mongoose.Schema({
projTitle: String,
todos: []
});
const Project = mongoose.model('Project', schema);
//add a project
app.post('/addProject', (req, res) => {
const collection = db.collection('projects')
**const proj = new Project({projTitle: req.body.projTitle});** // changes are here
collection.insertOne(proj, function(err, results) {
if (err){
console.log(err);
res.send('');
return
}
res.send(results.ops[0]) //retruns the new document
})
})
Please try to look at the code below.
const collection = db.collection('projects')
const proj = new Project({projTitle: req.body.projTitle}); //make changes here

How to add save another Schema data to a model?

I am using mongoose with Mongodb v3.4.3
Below is my image model code
const mongoose = require("mongoose");
const CoordinateSchema = require("./coordinate");
const ImageSchema = new mongoose.Schema({
image_filename: {
type: String,
required: true
},
image_url: {
type: String,
required: true
},
coordinates: [CoordinateSchema],
});
Below is my CoordinateSchema code
const mongoose = require("mongoose");
const CoordinateSchema = new mongoose.Schema({
coordinates : {
type: Array,
default: [],
}
});
module.exports = CoordinateSchema;
Below is my api js code running on express,
router.post('/receiveCoordinates.json', (req, res, next) => {
Image.findOneAndUpdate({image_filename:req.body.file_name}).then((image) => {
})
});
How to finish this code so I can store coordinates data in Image model.
Thanks.
UPDATE
To update the coordinates inside of findOneAndUpdate, you simply check that the returned document isn't undefined (which would mean your image wasn't found). Modify your api.js code like so:
router.post('/receiveCoordinates.json', (req, res, next) => {
Image.findOneAndUpdate({image_filename:req.body.file_name}).then((image) => {
if (!image) return Promise.reject(); //Image not found, reject the promise
image.where({_id: parent.children.id(_id)}).update({coordinates: req.body.coordinates}) //Needs to be an array
.then((coords) => {
if (!coords) return Promise.reject();
//If you reach this point, everything went as expected
});
}).catch(() => {
console.log('Error occurred');
);
});
Here's my guess why it isn't working.
In ImageSchema, you are sub-nesting an array of CoordinateSchema. But CoordinateSchema is a document which already contains an array.
This is probably not what you're looking for. If you're using mongoose version 4.2.0 or higher, you can nest CoordinateSchema inside of ImageSchema as a single document. Re-write your ImageSchema like this:
// ...
const ImageSchema = new mongoose.Schema({
// ...
coordinates: CoordinateSchema,
});
If this didn't work or doesn't resolve your issue, please let me know so we can work together to find a solution.

Categories

Resources