I have a route set up that uses a model called Todo like below:
app.get('/api/todos', function(req, res) {
Todo.find({},function(err, todos) {
if (err)
res.send(err);
console.log("number of todos " + todos.length);
res.json(todos); // return all todos in JSON format
});
});
however, todos.length is always 0, as it do not find any results.
When I run:
use test3
db.Todo.find()
I am sure I have connected to the same db. I can see the connection in mongod console.
My connection is inside config/db.js file:
module.exports = {
url : 'mongodb://localhost/test3'
}
The connection in my server.js is as follows:
var db = require('./config/db');
mongoose.connect(db.url);
in Mongo Shell I get 1 result. I am expecting this result to be return by the find query.
Is there something I have missed?
I am using Mongoose 3.6
Cheers
So what this very much looks like is that you have already created collections in an existing database and now you are trying to access these with mongoose models.
The problem is that mongoose uses some defaults which you may not be aware of, so the example you are showing from the shell is not the same as what mongoose is doing by default.
So you can either rename your collections to match what mongoose expects by default or change what mongoose does to match your existing names. In the latter case, you directly define the model names like so:
mongoose.model( "Todo", toDoSchema, "Todo" );
So the third argument to the method actually specifies the explicit name to use for the collection. Without this the assumed name under the default rules will be "todos".
Use either method in order yo make them match.
I faced this exact issue, I defined the Model for an already existing collection in MongoDB and to stop Mongoose from producing a collection name in plural I used this explicit collection option. Mistakenly I wrote Collection and this halted the results. So be careful while using explicit options, they are case sensitive.
Related
I want to obtain the value of a collection ID from a collection in cloud firestore if it exists:
export const getSlugs = async () => {
const document = await db
.doc(constDocumentRefs.slugs)
.collection('<collection_id>')
return ;
};
but this returns me collection reference, I can check if its empty by calling: document.get().empty method but not sure how do I get the value of collection, in case it is not empty.
My collection looks like this:
{
key1:1
key2:2
}
I want to keep it like return the actual value if collection exists otherwise return -1. Someone please help!
I can see two possible ways:
From the front-end:
As Dharmaraj mentioned in his comment, you need to fetch document(s) in the collection to see if the querySnapshot is empty or not. If the snapshot is empty, the collection does not exist. You can limit the query to only one document to minimize cost. For that you'll use the limit() method. And for checking if the QuerySnapshot contains a doc use the size property.
From a back-end:
The Admin SDKs offer a specific method to list collections, for example listCollections() for the Node.js Admin SDK (and listCollections() method of a DocumentReference for listing sub-collections). You can implement that in a Cloud Function and call it from your front-end: I wrote an article on this approach.
I was trying to console.log(record._id) all of records on my mongodb collection using Mongoose. I kept getting undefined for each of the _id values.
I struggled until I bumped into this post. Then I used console.dir to find the location of the _id and used that in my console.log:
MySchemaModel.find({}).then(function(records) {
records.forEach(function(record) {
console.log(record._doc._id); // <-- I added ._doc
});
});
But, this looks down-right hacky. Is there a better way to do this?
NOTE: This isn't just something that affects console.log. I'm just keeping the question narrow.
If you want to customize/edit record then you should use .lean() function.The .lean() function will turn it into a normal JavaScript object. If you don't use .lean() function then each record is still a mongoose document and _id behaves differently in that context. So can use like
MySchemaModel.find({}).lean().exec(function(error, records) {
records.forEach(function(record) {
console.log(record._id);
});
});
N.B: when use .exec() then first parameter used for error and second one for success data.
Mongoose assigns each of your schemas an id virtual getter by default
which returns the documents _id field cast to a string, or in the case
of ObjectIds, its hexString. If you don't want an id getter added to
your schema, you may disable it passing this option at schema
construction time.
Source: Mongoose Docs
var schema = new Schema({ name: String }, { id: false });
var Page = mongoose.model('Page', schema);
var p = new Page({ name: 'mongodb.org' });
console.log(p.id); // '50341373e894ad16347efe01'
I guess the issue is with .then promise, I have never seen that.
MySchemaModel.find({}).then
So just try simple .exec call with callback.
MySchemaModel.find({}).exec(function(records) {
records.forEach(function(record) {
console.log(record._id);
});
});
The problem is that each record is still a mongoose document and _id behaves differently in that context. The .lean() function will turn it into a normal JavaScript object.
MySchemaModel.find({}).lean().then(function(records) {
records.forEach(function(record) {
console.log(record._id);
});
});
you can also use the .map() method :
MySchemaModel.find({}).exec(function(records) {
console.log(records.map(record => record._id);
});
if you are using a model you don't get the full object but an instance of _doc as record
so you should directly
console.log(record._id)
or
console.log(record._id.valueOf())
but when you return record as response you get the full object so it's better to use .find().lean()
I am using existing Mongodb in meteor project. The existing mongo id represented by ObjectId(). When I try to find by _id, Meteor says ObjectId is not defined
JS:
Names = new Mongo.Collection('name_list', {idGeneration: 'MONGO'});
Names.find({"_id" : ObjectId("5539d9dcf046be5b2302aefc")}) //ReferenceError: ObjectId is not defined
The above JavaScript code is run in server.
You have to use new Mongo.ObjectID("5539d9dcf046be5b2302aefc"). See the meteor docs for some caveats.
If you want to save having to type new and Mongo. each time, you can define a function:
function ObjectId(hexString) { return new Mongo.ObjectID(hexString); };
and then the code you wrote will work.
You just need to require the ObjectId function from your mongo.
ObjectId = require('mongodb').ObjectID;
Then you can use it like that:
ObjectId("5539d9dcf046be5b2302aefc")
If you are using mongojs:
db.mycollection.findOne({
_id: mongojs.ObjectId('your object id')
}, function(err, doc) {
//do your stuff here.
})
Can't find any docs or posts for this, which may indicate I'm trying to do something incorrect.
Is it possible to use a Mongoose schema that is entirely virtual, i.e. not persisted to the db?
I have a number of models, most of which are persisted to db, but would like to consistently include models that are only retained in memory, not persisted?
The closest I can come up with is along these lines, but it will still persist objects with only an id attribute in the database. Simplified here:
// access_token.js
var schema = mongoose.Schema({});
schema.virtual('token').get(function() {
return 'abcde12345';
});
module.exports = mongoose.model('AccessToken', schema);
The idea in doing this is to abstract models so that the consuming part of the app does not need to be aware of whether a model is persisted to the database or only held in memory. Of course this could be achieved by creating the same object and methods as a plain object, but that approach would quickly become repetitive.
You could override (monkey patch) the Mongoose methods which save data (e.g. .save) but I suspect what you are trying to do is difficult/impossible.
You could take a look at sift.js, which is a query library to do in-memory querying.
https://github.com/crcn/sift.js
You can set a pre middleware for this model which always fails.
schema.pre('save', function (next) {
next(new Error('This can't be saved!');
});
So you will know when you are doing wrong.
The code I currently have is:
User.findOne(
{
"subUsers.email" : userEmail
},
{
subUsers : {
$elemMatch: {
email : userEmail }
}
},
function(err, user){
if(user){
var information = user.subUsers[0].information.id(id);
information.arrayA.push({someId : "something"});
user.save(callback(err)); // Also tried information.save()
// without luck
}
callback(err);
}
);
This doesn't return any kind of error, but when I check the DB, the new array element hasn't been pushed (the whole document is intact).
Any help would be much appreciated. Thanks!
You should probably check out the first faq, here: http://mongoosejs.com/docs/faq.html
Mongoose doesn't create getters/setters for array indexes; without them mongoose never gets
notified of the change and so doesn't know to persist the new value. The work-around is to
use [MongooseArray set][1] available in Mongoose >= 3.2.0.
So in your case, you want to add this third line
var information = user.subUsers[0].information.id(id);
information.arrayA.push({someId : "something"});
user.subUsers.set(0, information);
Or something like that.
As of today, Mongoose is currently not prepared for multilevel nesting in an atomic way.
Therefore, even if it's going back to a kind-of relational database, in this case it's better to split the nesting into at least 2 collections, and reference using the automatically generated ObjectId.