MongoDB data modeling: Document embedding dilemma |
If you think there might be any chance you would need get a total count
grouped by X, then stick with the 2nd method. Furthermore, if there is a
chance you might need it grouped by Y, that's not a bad practice to
denormalize your data and store Xs embedded in Ys along with Xs embedded in
Ys.
That is because mongo's poor performance with aggregating.
If you are sure you would not need any type of aggregation, 1st method
would be better in means of faster read/write and less disk space usage.
Or if you're not completely sure, store it like this: {x: "X", y: "Y",
count: 42}. Make sure you create index {x: 1, y: 1} for that. This way you
still keep an option to retrieve all documents by "X" or "Y". Note that
having {x: 1, y: 1} index means you dont need to create {x: 1} index for
querying b
|
embedding continuously growing document |
Having data stored in a single document wildly increasing is always wrong,
since the document has limit on its size (16MB).
I would recommend you to just reference user_id in activites collection,
like:
{
'_id': 'activity_id',
'user_id': 'user_id',
'time': ...,
'action: ...,
...
}
Make sure that index added for "user_id", and if you are always querying on
multiple fields, like {user_id: user_id, time: {$gt: blah blah}}, create
index on all the fields following the order in query, in this case:
(user_id: 1, time: -1) (if you always sort time DESCENDING)
|
embedding barcode generated with barby gem into the prawn document |
EDIT
In your InvoicePdf class, change the barcode method to:
def barcode
barcode = Barby::Code39.new @order.order_number
barcode.annotate_pdf(self)
end
The annotate_pdf method takes a Prawn::Document as its argument, which is
self here.
Original Answer
If you want to create a new pdf with your barcode, you can just do:
def barcode
_barcode = Barby::Code39.new(@order.order_number)
outputter = Barby::PrawnOutputter.new(_barcode)
outputter.to_pdf
end
Note that you can specify pdf options (including height, margins, page
size, etc.) on the new PrawnOutputter or on the to_pdf call. See the
documentation for more details:
https://github.com/toretore/barby/wiki/Outputters and
http://rdoc.info/github/toretore/barby/Barby/PrawnOutputter.
And if you want to write it to a file d
|
update nth document in a nested array document in mongodb |
Q1: If you update with permalink 'jaiho' instead of 'haha', it most
certainly updates the email;
> db.posts.update({"permalink" : "jaiho"},{$set:{"comments.0.email":1}})
> db.posts.find()
..., "email" : 1 },...
Q2: Same goes for this include;
> db.posts.update({"permalink" :
"jaiho"},{$inc:{"comments.0.num_likes":1}})
> db.posts.find()
..., "num_likes" : 1 },...
|
How to use Document#update in Mongoose? |
The Mongoose api is based on the underlying MongoDB query structure. In
this case, "doc" refers to a criteria for matching certain documents that
you want to update. The MongoDB docs explain this very clearly:
http://docs.mongodb.org/manual/core/write-operations/#update
So, let's say that you had a 'cars' collection, and you wanted to find all
documents (all cars) that had 3 wheels, and increment that value so those
cars had 4 wheels. In this case, "doc" is { wheels : 3 }, which returns
all three-wheeled cars in the collection. Here is the basic query in the
MongoDB shell:
> db.cars.update( { wheels : 3 }, { $inc : { wheels : 1 } } );
In Mongoose, you can add additional parameters for options and a callback
function, but that's the basic idea.
|
Is it possible to get the model from the document in mongoose? |
//Assume you have a `user` variable that is an instance of the User model,
//but this will work for any mongoose model instance
var Model = user.constructor;
//now you can do Model.find()....to run your query and this will work
//on any collection
//If you need the name of the model, it's user.constructor.modelName
|
MongoDB: If document exists VS If document does not exist |
The question is how you determine that "the document" exists? Usually,
you'd do this using a unique id. Now MongoDB's ObjectId comes to the rescue
because it contains a timestamp already. This can also be used in queries.
Instead of using an integer field User_ID, you might want to consider
calling the field _id and use the ObjectId data type so you get that
functionality for free.
> db.test.insert({"foo" : "test"});
{ "_id" : ObjectId("51cb763e58bb4077aea65b3d"), "foo" : "test" }
> var foo = db.test.findOne();
> foo._id.getTimestamp();
ISODate("2013-06-26T23:16:14Z")
|
Searching by key in mongodb/mongoose |
I just realised that the easy way to solve this is via the use of queries.
I could have easily done the following.
var field = 'appearance.elementary_one_reading';
Word.find().where(field, xxx).exec(callback);
|
Accessing mongodb(mongoose) and then do something with it |
You can use the Chrome developer tools or Firebug (firefox) to see what
values are being returned.
In your "for" loop, write debugger; and the code will break as it iterates
over the collection, or use the dev tools to set a break point.
|
Changing data in mongoose document |
I'm assuming that the user variable is a Model object, and that what you're
trying to achieve is to find a single user with a given username and code,
and set the banned property of that user to be true.
The first thing is that user.find will return an array of users, not just a
single user, so you'll want to use user.findOne instead.
user.findOne({ username: Username, code: Key}, function(err, userDoc) {
if (err)
{
// TODO: Handle the error!
}
if (! userDoc)
{
res.json('nope');
}
else
{
userDoc.banned = true;
userDoc.save(function (err) {
if (err)
{
// TODO: Handle the error!
}
res.json('yep');
});
}
})
This queries the database for a single docu
|
Mongoose: Collection not populating when used as a ref in another document |
Well, I figured out what the problem was. Kinda feeling like an idiot, but
here it is. I had both the Card and the Deck schema defined in the same
file since they were related and it made sense. At the end of the file, I
had the following:
module.exports = mongoose.model('Card', CardSchema);
module.exports = mongoose.model('Deck', DeckSchema);
Which meant that my Card schema was never being exposed because I wasn't
thinking when I exported the models. I moved the Deck schema to a separate
file, and now it all works.
Stupid mistake, but now I know. And knowing is half the battle.
|
Mongoose: doesn't put _id to embedded document |
When defining a schema you can specify options as a second parameter. Set
_id to false to disable auto _id.
var Embedded = new Schema({
some: String
}, {
_id: false
})
See the docs.
|
How to change sub document after finding with mongoose |
Sorry, I've resolved myself.
The problem is the order of declarating Schemas.
It worked if I tried this change.
/* first, children's schema */
var ChildSchema = new Schema({
name: String,
}, {_id: false});
/* seconds, parent's schema */
var UserSchema = new Schema({
name: String,
children: [ChildSchema],
});
|
mongoose save embedded document |
Because story.lines is not an Array. You probably need to update the Schema
to convert the lines to type Array in this way:
var LineSchema = new Schema({
text: {
type: String
},
entered_at: {
type: Date
},
user: {
id: {
type: Schema.ObjectId,
ref: 'Users'
}
}
});
var StorySchema = new Schema({
title: {
type: String,
required: true
},
users: {
id: {
type: Schema.ObjectId,
ref: 'Users'
},
creator: {
type: Boolean
}
},
maxlines: {
type: Number,
default: '10'
},
lines: [LineSchema],
created_date: {
type: Date,
default: Date.now
},
updated_date: {
type:
|
Mongoose.js unable to get an array from my document |
console will always print the array with objects as [object object].
pages is actually an array of object, So you can specify an index to the
pages array like this
console.log(user[0].pages[0]);
or if the pages array contain more than one element you want a regular for
loop
for (var i = 0; i<user[0].pages.length; i++) {
// use i as an array index
console.log(user[0].pages[i]);
}
|
Populate with inherited document in Mongoose |
Doh.. changing
var componentSchema = new Schema({
name: String
, desc: String
}, { discriminatorKey : '_type' })
to
var componentSchema = new Schema({
name: String
, desc: String
}, { collection : 'components', discriminatorKey : '_type' })
Fixes the issue. Not sure why.
|
Mongodb aggregation not working with mongoose |
Your query seems to be formatted correctly, I think you've just projected
"contacts" when you should have projected "list". I tried to format my
data like yours, and the following queries worked for me. In the shell:
db.accounts.aggregate(
{ $unwind:"$contacts" },
{ $group: {
_id: '$_id',
list: { $push:'$contacts.contactId' }
}
},
{ $project: { _id: 0, list: 1 }} )
or, using the mongoose framework,
Account.aggregate(
{ $unwind:"$contacts" },
{ $group: {
_id: '$_id',
list: { $push:'$contacts.contactId' }}},
{ $project: {
_id: 0,
list: 1 }},
function (err, res) {
if (err) //handle error;
console.log(res);
}
);
Since you've tried to suppress the "_id" field in the final output o
|
Insert or Update into MongoDB using mongoose.js |
I don't think your notion of a single route that will either update an
existing user or create a new one is a good idea. Instead, consider
following the REST design:
app.post('/api/users', createNewUser);
app.put('/api/users/:userId', updateUser);
createNewUser should just make a new user object with the proper attributes
and call save on it. updateUser can do User.update({_id:
req.params.userId}, fieldsToChange.... See if you can make that work to
start and don't add complications like checking for already registered
users until a simplistic create/update pair works OK and you feel
confident. Then you can evolve your code to be more robust and realistic,
but go step by step.
|
Mongodb / Mongoose poolSize recommendation |
This link would help you out , take a look Tuning node-mongodb-native
connection pool size.
It is difficult to predict the optimal poolsize for MongoDb , i use apache
benchmark tests (
ttp://www.cyberciti.biz/tips/howto-performance-benchmarks-a-web-server.html
) to test the servers performance and response for different values of
poolSize and get an approximation for what suits the best for given number
of concurrent requests for your server .
|
Why would Mongoose be saving the same document multiple times? |
So, I got it! I had a property in my schema named 'index':
names: [{
sort: String,
display: String,
brief: String,
nonLatin: String,
personal: { type: Boolean, default: false },
index: { type: Boolean, default: true }
}],
index is used in Mongoose to indicate whether a document property should be
indexed by MongoDB, and I was using it here as the name of a normal
document property. Changing the name of the property to showInIndex fixed
it. It was a foolish error, but I think that the effect it had is pretty
surprising so this answer may prove useful to someone in the future. (Does
anyone know why it caused this behavior instead of just throwing an error
or something?)
|
Mongoose - querying by comparing attributes of a document |
collection.find({ $where : "this.a < this.b" })
This query is not performant. Or
While inserting the document, insert a boolean true/false based on (a <
b ) or ( b < a ) and query for that boolean.
|
Mongoose update document Fail with findByIdAndUpdate |
findByIdAndUpdate is a static method:
var landmarkModel = mongoose.model('landmark', landmarkSchema,
'landmarks');
var lm = req.body;
delete lm._id;
landmarkModel.findByIdAndUpdate(req.body._id, lm, console.log);
Note that landmarkModel accepts plain js objects.
If you already have a mongoose object then it's best to use save instead:
var landmarkModel = mongoose.model('landmark', landmarkSchema,
'landmarks');
landmarkModel.findById(req.body._id, function (err, lm) {
if (err) return next(err);
//adding data to schema here, like: lm.name = req.body.name;
lm.save(console.log);
});
|
how to find any document in database with an object id with mongoose? |
Operations in MongoDB only always work on one collection. If you want to do
a find on multiple collections, then you need to run multiple queries - one
per collection. Of course, it's quite for Mongoose to implement a
convenience function for that, but I don't think it has, or should, as it
is against one of MongoDB's paradigms.
|
Querying an array inside a mongoose document |
You can use dot-separated paths in a query like so:
User.find({'devices.deviceRegistrationId': deviceRegistrationId}). If that
query doesn't match any documents, no user has that device. Note that mongo
is smart enough to test all members of the devices array when given a query
such as this. You can also add a user ID to your query conditions if you
want to check a specific user.
|
Creating relationships in MongoDB using Mongoose (in Node.js) |
//problem 1: `find` returns a list of results. You just need findById
var query = Category.findById(parentCategoryID);
query.select('name');
query.exec(function (err, parentCategory) {
//Problem 2: don't ignore errors. Handle them first and short-circuit
return
if (err) {
console.err(err);
return;
}
console.log("Fetched parentCategory: "+parentCategory+"..
parentCategory._id: "+parentCategory._id);
//problem 3: mongoose will do the right thing with your schema here
//all you need is
var category = new Category();
category.name = name;
category.parent = parentCategory;
//and don't forget
category.save(...callback....);
}
Also note if you have a schema, and you assign something that does not
match the schema, mongoose will just drop the
|
Mongodb (using mongoose) expiresAfterSeconds (TTL) doesn't seem to work |
I have tested this feature and it works fine with 2.4.4 MongoDB.
Having taken a closer look at your indexes I realized the problem is a
small typo.
My TTL index which works:
{
"v" : 1,
"key" : {
"test_expira" : 1
},
"ns" : "test.usuarios",
"name" : "test_expira_1",
"expireAfterSeconds" : 120,
"background" : true,
"safe" : true
}
Your TTL index which does not work:
{
"v" : 1,
"key" : {
"test_expira" : 1
},
"ns" : "dbnamehere.usuarios",
"name" : "test_expira_1",
"expiresAfterSeconds" : 120,
"background" : true,
"safe" : true
}
Note the correct keyname for TTL index is "expireAfterSeconds" where yours
has an extra letter and is "expiresAfterSeconds".
|
Mongoose doesn't save data to the MongoDB |
It looks like the problem is in your news schema's save middleware.
newsSchema.pre('save', function(next){
if( !this.addedOn ) this.addedOn = new Date();
if( !this.addedBy ) this.addedBy = {first: "admin", last: "admin"};
});
Your function receives a "next" callback which you must execute to let
mongoose know that you are done and ready to save the document. Since
you're not calling it, it could explain why you get nothing saved, and also
no errors.
Try just calling next like this:
newsSchema.pre('save', function(next){
if( !this.addedOn ) this.addedOn = new Date();
if( !this.addedBy ) this.addedBy = {first: "admin", last: "admin"};
next();
});
|
Getting data from mongodb/mongoose using predefined functions |
You can't do it without callbacks, but you can use an async flow control
library like async to help manage the nest of callbacks. In this case you
probably want to use async.parallel.
Using that you can do something like:
users.get(base_URL, (req, res) => {
var data = {
title: "Yes, got it right"
};
async.parallel([
(callback) => {
UserModel.find({}, (err, docs) {
data.user_list = docs;
callback(err);
});
},
(callback) => {
// Other query that populates another field in data
}
], (err, results) => {
// Called after all parallel functions have called their callback
res.render('<some_jade_file_here>', data);
});
});
|
Search for most common "data" with mongoose, mongodb |
You are correct to want to use MongoDB's aggregation framework. Aggregation
will give you the output you are looking for if used correctly. If you are
looking for just a list of the _id's of all users' favorite workouts, then
I believe that you would need to add an additional $group operation to your
pipeline:
db.users.aggregate(
{ $unwind : "$favoriteWorkouts" },
{ $group : { _id : "$favoriteWorkouts", number : { $sum : 1 } } },
{ $sort : { number : -1 } },
{ $group : { _id : "oneDocumentWithWorkoutArray", hot : { $push :
"$_id" } } }
)
This will yield a document of the following form, with the workout ids
listed by popularity:
{
"_id" : "oneDocumentWithWorkoutArray",
"hot" : [
"workout6",
"workout1",
"workout5",
"workout4",
|
Node.js / MongoDB / Mongoose: Buffer Comparison |
It is not a good idea to query for your image by the node.js Buffer that
contains the image data. You're right that it's probably an issue between
the BSON binary data type and a node Buffer, but does your application
really require such a comparison?
Instead, I'd add an imageID or slug field to your schema, add an index to
this field, and query on it instead of bin in your findOneAndUpdate call:
var imageSchema = new Schema({
imageID: { type: String, index: { unique: true }},
mime: String,
bin: Buffer,
uses : [{type: Schema.Types.ObjectId}]
});
|
Updating array within mongodb record with mongoose |
It would help if you explained your intent here as naming a property
"array" conveys nothing about its purpose. I guess from your code you hope
to go and set the score of each item there to zero. Note your save is
currently being ignored because you can only save top-level mongoose
documents, not nested documents.
Certain find-and-modify operations on arrays can be done with a single
database command using the Array Update Operators like $push, $addToSet,
etc. However I don't see any operators that can directly make your desired
change in a single operation. Thus I think you need to find your record,
alter the array date, and save it. (Note findOne is a convenience function
you can use if you only care about the first match, which seems to be the
case for you).
Record.findOne({ 'owner':
|
Easiest way to copy/clone a mongoose document instance? |
Can you clarify what you mean by "copy/clone"? Are you going trying to
create a duplicate document in the database? Or are you just trying to have
two vars in your program that have duplicate data?
If you just do:
Model.findById(yourid).exec(
function(err, doc) {
var x = doc;
Model.findById(yourid).exec(
function(err, doc2) {
var y = doc2;
// right now, x.name and y.name are the same
x.name = "name_x";
y.name = "name_y";
console.log(x.name); // prints "name_x"
console.log(y.name); // prints "name_y"
});
});
In this case, x and y will be two "copies" of the same document within your
program.
Alternatively, if you wanted to insert a new copy
|
Better way to loop through grabbing user details in Mongoose/MongoDB |
Use a reference in your Notification schema, and then populate it, as per
the Mongoose Docs.
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId,
var notificationSchema = new Schema({
initiator: { type: ObjectId, ref: 'User' }
});
var Notification = mongoose.model('Notification', notificationSchema);
You can then use Mongoose's query populate method:
app.get('/notifications/:id', function(req, res) {
Notification
.find({ initiator: req.params.id })
.select('_id type initiatorId')
.populate('initiator')
.exec(function(err, notifications) {
if (err) return handleError(err);
// do something with notifications
});
});
However, I'm slightly confused why the id is a user id (and not a
notification id) –
|
Using find() with geospatial coordinates in Mongoose (NodeJS+MongoDB) |
I had to use the Mixed type and added some custom validation to ensure
values were arrays and had a length of 2. I also checked for empty arrays
and converted them to nulls because this is required when using sparse
indices with 2dsphere. (Mongoose helpfully sets array fields to [] for
you, which is not a valid coordinate!)
var schema = new mongoose.Schema({
location: { type: {}, index: '2dsphere', sparse: true }
});
schema.pre('save', function (next) {
var value = that.get('location');
if (value === null) return next();
if (value === undefined) return next();
if (!Array.isArray(value)) return next(new Error('Coordinates must be an
array'));
if (value.length === 0) return that.set(path, undefined);
if (value.length !== 2) return next(new Error('Coordinates should be of
|
Cannot return values to response with mongoose/mongodb and nodejs |
Actually in your code you are passing a callback, which is never handled in
function userSchema.statics.list
You can try the following code:
userSchema.statics.list = function (calbck) {
this.find(function (err, users) {
if (!err) {
calbck(null, users); // this is firing the call back and first
parameter should be always error object (according to guidelines). Here no
error, so pass null (we can't skip)
} else {
return calbck(err, null); //here no result. But error object.
(Here second parameter is optional if skipped by default it will be
undefined in callback function)
}
});
}
Accordingly, you should change the callback which is passed to this
function. i.e.
exports.list = function (req, res){
UserModel.list(function(err, users
|
Mongoose/MongoDB result fields appear undefined in Javascript |
You don't have whitespace or funny characters in ' title', do you? They can
be defined if you've quoted identifiers into the object/map definition.
For example:
var problem = {
' title': 'Foo',
'content': 'Bar'
};
That might cause console.log(item) to display similar to what you're
expecting, but cause your undefined problem when you access the title
property without it's preceding space.
|
Query nested object dynamically in Mongodb + Mongoose.js |
var user_id = req.params.id;
var query = {};
query['ratings.' + user_id] = {$exists: true};
Item.find(query, function(err, items) { ... });
The key in the object you send to Item.find have to be a string. To
construct a string of any arbitrary values you have to first create the
object and then use the bracket notation to define it (that is:
query[anything+here] = data).
|
MongoDB (and Mongoose.js): Does the order of query conditions matter? |
I'm a little confused by your question, simply because the index you
provide ({ first_name: 1, archived: 1 }) is a compound index. All of the
following queries will make use of that compound index:
conditions = { archived: false, first_name: "Billy" };
conditions = { first_name: "Billy", archived: false };
conditions = { first_name: "Billy" };
Now, let's assume we have two separate indexes, { first_name: 1 } and {
archived: 1 }. In this case, MongoDB will do query optimization to
determine which index is the most efficient to use. You can read more about
the query optimization performed by MongoDB here.
The MongoDB query optimizer will thus likely use the same index for both of
the multicondition queries you provided:
conditions = { archived: false, first_name: "Billy" };
conditions
|
Populating an array when creating a record in MongoDB with mongoose |
I've also encountered issues with populating array, the schema you defined
will create a sub-doc for each array element (try dumping the array).
Try changing the schema to:
emails: [ type: mongoose.Schema.Types.ObjectId ]
and use
Member.findOne().populate({ path: 'emails', model: 'Email' }).exec(function
(err, member) {
res.json(200, member);
});
to populate the array.
|
Can't get mongoose/mongoDB to throw a 11000 (Duplicate Error) |
My guess is that your index didn't stick, which you later fixed the syntax.
db.users.getIndexes()
Use that to verify that there are indexes on the collection next time.
|