Mongoose can't query only a database - node.js

I'm facing a Mongoose's strange behaviour.
Let's analyse this simple stupid code.
var mongoose = require('mongoose');
mongoose.connect('mongodb://127.0.0.1/sodatest', {
useMongoClient: true
});
var db = mongoose.connection;
var OriginalSchema = mongoose.Schema({
addedd: Date,
endPoint: Object,
inserted: Number,
total: Number
});
var OtherTestSchema = mongoose.Schema({
what: String,
modified_at: Date
});
var EndPointInTheDb = mongoose.model('aaa', OriginalSchema);
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
console.log("we are connected!");
});
EndPointInTheDb.find({}, (err: String, exit: any) => {
console.log("Errore : " + err)
console.log(exit)
});
It fails and return
we are connected!
*********************
Error : null
[]
*********************
It fails because the collection "aaa" has 15 elements.
If I change the db "sodatest" with any other ( except for another one with a lowercase name ) and 'aaa' with another collection name, it does't care if I use the correct case, it returns a correct result.
we are connected!
*********************
Error : null
[ { _id: 59f76203592b426a16b8b32f,
modified_at: 2017-10-30T17:31:47.622Z,
last_position: 5,
what: 'CONTATOREGEOKEY',
__v: 0 } ]
*********************
(it works also with multiple elements)
I've tried to copy the db in another one,
db.copyDatabase("sodatest","Prova14")
with a name with at least an uppercase char (Prova14), but again no result.
I've checked for hours if I've misspelled a name, but really, I'm sure of it.
I can't understand why it works with any other db ( 14 others with heterogeneous schema) also if I use a schema ("OtherTestSchema" ) that does not match with the collection real schema.... but not with sodatest.
Any Idea ?

Mongoose automatically adds an 's' at the end of the collection name if one is not provided. For Example:
// This will create a collection called 'aaas' since 'aaa' is passed as the
// model name
var EndPointInTheDb = mongoose.model('aaa', OriginalSchema);
// This is how you declare your collection name with a custom collection 'aaa'
var CorrectEndPointInTheDbToCollection = mongoose.model('aaa', OriginalSchema, 'aaa');
CorrectEndPointInTheDbToCollection.find({}, function(err, docs){
console.log(docs)
})
So the initializer for mongoose is mongoose.model('model name', Schema, 'optional collection name'). Highly recommend you pass in the collection name so you know it's pointing to the right collection

Related

insert values ​to a table in mongodb with nodejs

I created a table in mongodb and I want to add values ​​to it via nodejs, this is my code:
mongoose.connect('mongodb://localhost:27017/attendances', { useNewUrlParser: true });
const Schema = mongoose.Schema;
const dataSchema = new Schema({ userId: String, date: Date, start: Date,end:Date });
const dataModel = mongoose.model("datas",dataSchema);
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
console.log('connect to DB');
});
router.post('/add', (req, res) => {
const {userId,date,start} = req.body;
console.log('add',userId,date,start);
dataModel.create({userId:userId,date:date,start:start},function (err, result) {
});
dataModel.findOne({userId:userId,date:new Date().toDateString()},function(err,result){
console.log('findOne',result);
res.end(result);
})
});
He does not add my values ​​to the table.
Where's my mistake?
This is my err:
Error: datas validation failed: start: Cast to date failed for value
"11:56:26" at path "start"
There is a more than one mistake.
First:
Your Object Validation fails. I need to know whats inside your start variable.
Second:
You use two different dates one is date variable other one is generated by querying with date:new Date().toDateString()
Third:
Javascript works asynchronously. You cannot know when your findOne triggers after object successfully created.

Beginner Issue with Mongoose and MongoDB

I'm new to Node, along with Mongoose and MongoDB. I'm trying to test inserting data into one of the collections in a database on MongoDB Atlas. However, the code somehow inserts the data into the wrong database. I intend to insert data into the 'test' collection in the 'quizzard' database. However, a new collection called 'tests' was created within quizzard where the data was placed. When I tried it again, it started inserting data into another database called 'test' and created a collection called 'tests', where the data is still being placed.
var link = "mongodb+srv://<user>:<password>#quizzard-dp0b2.mongodb.net/test?retryWrites=true&w=majority";
// changed to <user> and <password> for privacy reasons
mongoose.connect(link, {
useNewUrlParser: true,
useUnifiedTopology: true
});
mongoose.connection.on('connected', () => {
console.log('Connected');
});
const Schema = mongoose.Schema;
const TestSchema = new Schema({
_id: Number,
data: String
});
//TestSchema.set('database', 'test');
//TestSchema.set('collection', 'test');
const Test = mongoose.model('Test', TestSchema);
const data = {
_id: 11,
data: "why???"
};
const newTest = new Test(data);
newTest.save((error) => {
if(error){
console.log("An error has occured");
} else {
console.log("Action performed");
}
});
You need to change the link; after the first slash, you choose which DB you want to use.
Examples
// DB NAME youinsertinheredbname
var link = "mongodb+srv://<user>:<password>#quizzard-dp0b2.mongodb.net/youinsertinheredbname?retryWrites=true&w=majority";
// DB NAME stackoverflow
var link = "mongodb+srv://<user>:<password>#quizzard-dp0b2.mongodb.net/stackoverflow?retryWrites=true&w=majority";

Mongoose findById returns null even with valid id

I have already seen the discussion about the following question with a similar title
mongoose 'findById' returns null with valid id
But my problem is not the database name since all my other connections with the same database in fact the queries on the same collection are working fine.
I am using mongoose 4.13.6, node js 6.11 and mongo 3.4.
It is a post request .
var query=req.body;
I am sending the search parameters as
var findFruit =
{
_id:query._id
}
When I print my findFruit I get :
_id:'5a1cf77920701c1f0aafb85e'
The controller function for this is :
Fruit.findById(findFruit._id,function(err,fruit){
if( _.isNull(err) ){
var response = genRes.generateResponse(true,"found successfully");
callback(response);
}
else{
var response = genRes.generateResponse(false,"there occured some error : "+err);
callback(response);
}
})
I even tried find
Fruit.find(findFruit,function(err,fruit){
if( _.isNull(err) ){
var response = genRes.generateResponse(true,"found successfully");
callback(response);
}
else{
var response = genRes.generateResponse(false,"there occured some error : "+err);
callback(response);
}
})
The collection for sure has the entry under this id .
I went through this git issue as well https://github.com/Automattic/mongoose/issues/3079
Unfortunately I cannot downgrade mongoose as it might affect multiple other working functions.
Edit :
I tried creating ObjectId like :
var mongoose = require('mongoose');
var ObjectID = require('mongodb').ObjectID;
var objectId = new ObjectID();
// Convert the object id to a hex string
var originalHex = objectId.toHexString();
// Create a new ObjectID using the createFromHexString function
var newObjectId = new ObjectID.createFromHexString(query._id);
The model file :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var FruitSchema = new Schema({
name : {type : String, unique : true},
color : {type : String}
});
module.exports = mongoose.model('Fruit', FruitSchema);
All my findById("id") calls returned null.
When looking at the collection with Compass I realized that all my _id elements were Strings. Note that the entire collection was imported.
I created a new element in Compass and the _id was created as ObjectId! and when I called findById("id") with that element's id it worked!
My conclusion is that there is obviously a bug with import. I have not found a way to convert the string _id fields to ObjectId's in the actual collection.
All my findById("id") calls returned null, when _id elements are Strings.
In the first place:
Check your mongodb database, if _id is stored as String, findById(id) can not find since it identifies ObjectId. If you've used import database by using mongoimport command and including _id in JSON:
Solution 1:
modify your JSON and for each document, change _id for instance:
_id: "5a68fde3f09ad7646ddec17e" to the following and run mongoimport again:
"_id": { "$oid": "5a68fde3f09ad7646ddec17e" }
Solution 2:
delete _id in the JSON file, drop collection and import again. Mongo will auto-create _id.
After any of solutions above, findById("id") will work.
Secondly:
Specifically in such cases where your _id elements are string, might be a better idea to use mongodb package: npm i mongodb
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, function (err, db) {
if (err) throw err;
var dbo = db.db("your_db_name");
dbo.collection("fruits_collection")
.find({_id:'5a1cf77920701c1f0aafb85e'})
//.find({_id:'5a1cf77920701c1f0aafb85e'}, { projection: { _id: 0, name: 1, color: 1} }) // to select specific columns desired
.toArray(function (err, result) {
if (err) throw err;
console.log(result);
db.close();
});
});
The above simple code, assumed you manage error handling yourself, either through try-catch, or
sending 404 as status code, or redirect to error page template, depending on whether the code is embedded in the Express route handler or not.
Hope this helped .. :)
Still trying to figure out why findById didn't work for me but the following piece of code did it
var mongoose = require('mongoose');
var newObjectId=new mongoose.Types.ObjectId(query._id);
var params={
'_id':newObjectId
}
Fruit.find(params).exec(function (err,fruit) {
if( _.isNull(err) ){
var response = genRes.generateResponse(true,"found successfully");
callback(response);
}
else{
var response = genRes.generateResponse(false,"there occured some error : "+err);
callback(response);
}
})
#Shoom. Yes, worked for me, thanks. findById() expects ObjectID, not a String.
I did not have a constraint to create documents with a specific id, so I imported with no _id. The db had newly-assigned _id as ObjectID.
findById(id), (and updateOne({ _id: id }, ...), started working as expected.

Result of mongoose.save is incorrect when adding item to mixed schema array

Following is a function that shows the issue:
var mongoose = require('mongoose');
var connection = mongoose.createConnection('mongodb://localhost:27017');
connection.once('open', function () {
var schema = new mongoose.Schema({
obj: [{}] //mongoose.Schema.Types.Mixed
});
var Model = connection.model('mtest', schema);
var model = new Model({
obj: [{ name: 'Original' }]
});
model.save(function (err, res) {
console.log('result 1', res);
Model.findOne({_id: res._id}, function (err, res) {
res.obj[0].name = 'Modified';
res.obj.push({ name: 'other' });
//res.markModified('obj'); // using markModified does not help
res.save(function (err, res) {
console.log('result 2', res);
connection.close();
process.exit();
});
});
})
});
The output of "result 2" shows "Modified" for the first item in "obj": obj: [ { name: 'Modified' }, { name: 'other' } ].
However, in the database the value of the first item is still "Original".
This only happens when pushing a second item into the array (otherwise the first item is indeed modified).
Adding markModified does resolve the issue.
I'm using an array of empty objects types in the schema because in reality this use case deals with with schemas that inherit from each other, so no single schema can be used here.
Is it a bug? The only workaround I've found is to clear the array and add all the items again. I'd like to know if there's a better solution.
You could either alter your markModified call to identify the index of the element you changed "outside" of the array access methods:
res.obj[0].name = 'Modified';
res.obj.push({ name: 'other' });
res.markModified('obj.0');
Or switch to using the set array access method to alert name (which looks pretty goofy, but does work):
res.obj[0].name = 'Modified';
res.obj.set(0, res.obj[0]);
res.obj.push({ name: 'other' });

MongoDB: handling auto-incrementing model id's instead of Mongo's native ObjectID

Due to a management decision, we are using userId for the users collection, postId for the posts collection, and topicId for the topics collection, instead of '_id' for each collection as the unique identifier.
This causes a few problems getting started - one of the problems I have encountered is with upserts -
Using Mongoose, we have a schema that restricts userId to be a unique value - but when doing an update on a user model, with upsert set to true, MongoDB appears to only look at the ObjectIds of a collection to see if the same one exists - it doesn't check to see if a model already exists with the same userId - therefore Mongo does an insert instead of an update.
let me illustrate this with some data:
let's say the user's collection has one document:
{
_id:'561b0fad638e99481ab6d84a'
userId:3,
name:'foo'
}
we then run:
User.update({userId:3},{"$set":{name:'bar'},{upsert:true},function(err,resp){
if(err){
// "errMessage": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: app42153482.users.$userId_1 dup key: { : 3 }",
}
});
one would think that MongoDB would find the existing document with userId:3 and udpate it, so there must be something I am doing wrong since it's giving me the duplicate key error?
Typically the default value ObjectId is more ideal for the _id. Here, in this situation you can either override the default _id or you can have your own field for id(like userId in your case).
Use a separate counters collection to track the last number sequence used. The _id field contains the sequence name and the seq field contains the last value of the sequence.
Insert into the counters collection, the initial value for the userid:
db.counters.insert( {
_id: "userid",
seq: 0 } )
Create a getNextSequence function that accepts a name of the sequence. The function uses the findAndModify() method to atomically increment the seq value and return this new value:
function getNextSequence(name) {
var ret = db.counters.findAndModify(
{
query: { _id: name },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
Use this getNextSequence() function during insert().
db.users.insert(
{
_id: getNextSequence("userid"),
name: "Sarah C."
}
)
db.users.insert(
{
_id: getNextSequence("userid"),
name: "Bob D."
}
)
This way you can maintain as many sequences as you want in the same counter collection. For the upsert issue, check out the Optimistic Loop block in this link Create an auto-increment sequence field.
The second approach is to use a mongoose middleware like mongodb-autoincrement.
Hope it helps.
I don't know which versions of MongoDB and Mongoose you are using, but I couldn't reproduce your problem with MongoDB 3.0 and Mongoose 4.1.10.
I made a sample for you which will create and save a new user, update (using upsert) it, and create another one through an upsert. Try running this code:
"use strict";
var mongoose=require("mongoose");
var Schema = require('mongoose').Schema;
var ObjectId = mongoose.Schema.Types.ObjectId;
// Connect to test
mongoose.connect("mongodb://localhost:27017/test");
// Lets create your schema
var userSchema = new Schema({
_id: ObjectId,
userId: {type: Number, unique: true },
name: String
});
var User = mongoose.model("User", userSchema, "Users");
User.remove() // Let's prune our collection to start clean
.then( function() {
// Create our sample record
var myUser = new User({
_id:'561b0fad638e99481ab6d84a',
userId:3,
name:'foo'
});
return myUser.save();
})
.then( function() {
// Now its time to update (upsert userId 3)
return User.update({userId:3},{"$set":{name:'bar'}},{upsert:true});
})
.then( function() {
// Now its time to insert (upsert userId 4)
return User.update({userId:4},{"$set":{name:'bee'}},{upsert:true});
})
.then( function() {
// Lets show what we have inserted
return User.find().then(function(data) {console.log(data)});
})
.catch( function(err) {
// Show errors if anything goes wrong
console.error("ERROR", err);
})
.then( function() {
mongoose.disconnect();
});
Following the documentation (of MongoDB 3.0) upsert:true will only not insert a non-existing document if your query conditions match on the _id field.
See: https://docs.mongodb.org/manual/reference/method/db.collection.update/#mongodb30-upsert-id
Why are you not using the user_name for a user as unique id?
Because auto-incrementing fields as ids are a bad practice to use in a mongodb environment, especially if you want to use sharding
=> all your inserts will occur on the latest shard
=> the mongodb cluster will have to rebalance often / redistribute the data around.
(Currently this will not occur on your system as you still use the generated _id field)
You can off course also create a unique index on the user_id field:
https://docs.mongodb.org/manual/core/index-unique/#index-type-unique

Resources