I'm trying to Query my MongoDB with Mongoose.
I search for the string 13 in the field eClassSegment in the collection eclasses. Something is printed in the console. Why?
Code:
var mongoose = require('mongoose'),
EClass = require('./models/eclass');
mongoose.Promise = require('bluebird');
EClass.findOne({ 'eClassSegment': '13' }, 'eClassSegment', function (err, result) {
if (err) {
console.log("Error: ", err);
}
console.log('All eClassSegments that equals 13: ', result);
});
The Moongoose Schema :
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
// Defining Mongoose Schema
const eClassSchema = mongoose.Schema({
eclassSegment: { type: String, min: 2, max: 2 },
eclassMainGroup: { type: String, min: 2, max: 2 },
eclassGroup: { type: String, min: 2, max: 2 },
eclassCommodityClass: { type: String, min: 2, max: 2 },
preferredName: { type: String, max: 80 },
definition: { type: String, max: 1023 },
level: { type: String, min: 1, max: 1 },
mkSubclass: { type: String, min: 1, max: 1 },
mkKeyword: { type: String, min: 1, max: 1 }
});
// Create mongoose model
module.exports = mongoose.model('EClass', eClassSchema);
Example of an document in the MongoDB (I have many documents with eClassSegment = '13'..)
{
"_id" : ObjectId("58e5d8d8fc0788063e587e1a"),
"mkKeyword" : "0",
"mkSubclass" : "1",
"level" : "1",
"definition" : "Services for the development of a product basically on the basis of service contracts or contract development",
"preferredName" : "Development (Service)",
"eclassCommodityClass" : "00",
"eclassGroup" : "00",
"eclassMainGroup" : "00",
"eclassSegment" : "13",
"__v" : 0
}
So you are trying to search for eClassSegment.
But the key in the schema and the database is eclassSegment
I forgot to connect to the database... Need some coffe... :-)
Here is the solution!
var mongoose = require('mongoose'),
EClass = require('./models/eclass');
mongoose.Promise = require('bluebird');
mongoose.connect('mongodb://localhost/eclassCSV');
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
var geteClass = function() {
EClass.findOne({ 'eclassSegment': '13' }, 'eclassSegment', function (err, result) {
if (err) {
console.log('Error: ', err);
}
console.log('All eclassSegments that equals 13: ', result);
})
.then(function() {
mongoose.disconnect();
})
.catch(function(err) {
console.log('There was an error', err);
});
};
geteClass();
});
Example of a Console.log of result
All eclassSegments that equals 13: { _id: 58e5d8d8fc0788063e587e1a, eclassSegment: '13' }
Related
I have a very basic schema which has another object called Vehicle, inside
let rentSchema = new Schema({
code: {
type: Number
},
vehicle: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Vehicle'
},
ongoing: {
type: Boolean,
default: false
}
}, {collection: 'RentCollection'});
Find all in the controller
exports.getRent = function (req, res) {
// Find in the DB
rentSchema.find({}, function (err, rent) {
if (err) res.status(400).send(err);
res.json(rent);
});
};
The response comes as an array of Rents but Vehicle object is missing from the Object Rent. Why is that?
_id: "5e04c19d0a0a100f58bd64b5"
__v: 0
ongoing: false
Here is step by step explanations to make it work:
1-) First you need to create a model and export it like this:
rent.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
let rentSchema = new Schema(
{
code: {
type: Number
},
vehicle: {
type: mongoose.Schema.Types.ObjectId,
ref: "Vehicle"
},
ongoing: {
type: Boolean,
default: false
}
},
{ collection: "RentCollection" }
);
module.exports = mongoose.model("Rent", rentSchema);
2-) Let's say you have this Vehicle model:
vehicle.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
let vehicleSchema = new Schema(
{
name: String
},
{ collection: "VehicleCollection" }
);
module.exports = mongoose.model("Vehicle", vehicleSchema);
3-) First let's create a vehicle like this in the VehicleCollection like this:
{
"_id": "5e0f465205515667746fd51a",
"name": "Vehicle 1",
"__v": 0
}
4-) Then let's create a rent document in RentCollection using this vehicle id like this:
{
"ongoing": false,
"_id": "5e0f46b805515667746fd51d",
"code": 1,
"vehicle": "5e0f465205515667746fd51a",
"__v": 0
}
5-) Now we can use the following code, to populate the vehicle with the rents.
const Rent = require("../models/rent"); //todo: change to path to the rent.js
exports.getRent = function(req, res) {
Rent.find({})
.populate("vehicle")
.exec(function(err, rent) {
if (err) {
res.status(500).send(err);
} else {
if (!rent) {
res.status(404).send("No rent found");
} else {
res.json(rent);
}
}
});
};
6-) The result will be:
[
{
"ongoing": false,
"_id": "5e0f46b805515667746fd51d",
"code": 1,
"vehicle": {
"_id": "5e0f465205515667746fd51a",
"name": "Vehicle 1",
"__v": 0
},
"__v": 0
}
]
You will have to use the populate method to populate a vehicle object.
From docs:
rentSchema.
findOne({}).
populate('vehicle').
exec(function (err, obj) {
if (err) return handleError(err);
console.log(obj);
});
Also in your current code, you havent setted up model:
RentCollection = mongoose.model('RentCollection', rentSchema);
I am writing code with node.js. Quite new to this and the problem is that mongoose returns an empty array. There must be a mistake somewhere in this code, but I cannot find it. Any ideas?
Dresses schema
var dressesSchema = mongoose.Schema({
title:{
type: String,
required: true
},
description:{
type: String,
required: true
}
});
var Dress = module.exports = mongoose.model('Dress', dressesSchema);
Get dresses from database
module.exports.getDresses = function(callback, limit){
Dress.find(callback).limit(limit);
};
Dress = require('./models/dress');
app.get('/api/dresses', function(req, res){
Dress.getDresses(function(err, dresses){
if(err){
throw err;
}
res.json(dresses);
});
});
example how to use find via mongoose :
// named john and at least 18
MyModel.find({ name: 'john', age: { $gte: 18 }});
// executes immediately, passing results to callback
MyModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) {});
// name LIKE john and only selecting the "name" and "friends" fields, executing immediately
MyModel.find({ name: /john/i }, 'name friends', function (err, docs) { })
// passing options
MyModel.find({ name: /john/i }, null, { skip: 10 })
// passing options and executing immediately
MyModel.find({ name: /john/i }, null, { skip: 10 }, function (err, docs) {});
// executing a query explicitly
var query = MyModel.find({ name: /john/i }, null, { skip: 10 })
query.exec(function (err, docs) {});
// using the promise returned from executing a query
var query = MyModel.find({ name: /john/i }, null, { skip: 10 });
var promise = query.exec();
promise.addBack(function (err, docs) {});
taken from link
try this:
Dresses schema :
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const Dress= new Schema({
title:{
type: String,
required: true
},
description:{
type: String,
required: true
},
price:{
type: String
},
stock:{
type: String
},
location:{
country:{
type: String
},
city:{
type: String
},
street:{
type: String
},
lon:{
type: String
},
lat:{
type: String
}
}
});
module.exports = mongoose.model("dress", Dress);
Get dresses from database:
const {Dress} = require('./models/dress');
Dress.find().then(result => {
console.log(result);
});
I'm (trying) to build an API system using mongoose, express and node. Right now I've two Schemas: user and event.
User Schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
profileImage: {
data: Buffer,
contentType: String
},
isAdmin: {
type: Boolean,
'default': false
},
bio: {
type: String,
'default': ''
}
});
mongoose.model('User', userSchema);
Event Schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = mongoose.model('User').schema;
var eventSchema = new Schema({
title: {
type: String,
required: true
},
date: {
type: Date,
'default': Date.now
},
place: {
type: String,
required: true
},
distance: {
type: String,
'default': '-1'
},
eventType: {
type: Number,
'default': 2 /* 0 = Asfalto, 1 = Trail, 2 = Otros */
},
attenders: [userSchema],
comment: {
type: String,
'default': ''
}
});
mongoose.model('Event', eventSchema);
And then I've defined a controller to manage POST requests over a certain endpoint. On my controller I only checks 'title' and 'place' fields on Event requests, like this:
if (!req.body.title) {
response.sendJSON(res, 400, null, {"message": "title param is needed"});
return;
}
if (!req.body.place) {
response.sendJSON(res, 400, null, {"message": "place param is needed"});
return;
}
Events
.create({
title: req.body.title,
place: req.body.place
}, function(err, event) {
if (err) {
response.sendJSON(res, 400, null, err);
} else {
response.sendJSON(res, 201, event, null);
}
});
};
So I'm sending a request, using a 'title':'Example title', 'place':'Spain' as body params.
The first request creates new event successfully, but the nexts requests show me this error:
"status": 400,
"error": {
"code": 11000,
"index": 0,
"errmsg": "E11000 duplicate key error index: som-passatge.events.$attenders.email_1 dup key: { : null }",
"op": {
"title": "TÃtulo de evento 22",
"place": "Valencia",
"_id": "56cc905d496141587dc47caf",
"comment": "",
"attenders": [],
"eventType": 2,
"distance": "-1",
"date": "2016-02-23T17:01:17.650Z",
"__v": 0
}
},
"response": null
I don't know what I'm doing wrong...
I have an admin that creates an item (a bourbon), that users can give a comment on and rating within that comment. I was able to aggregate the comments, but was not able to display newly-created bourbons, only those already seeded that already had ratings. i've tried to implement something similar to this thread: referenced thread, but i'm am not doing something correct.
I'm a noob, and mainly play in the frontend, and am very confused about how I should change this sample code into actual production code. I see what each function is doing, but still fuzzy on it.
Should I do an async.each and set the aggregate function as the iterator..? I know this is busted. I've tried a few things now. Keep getting a 500 error, nothing on the console.log. Any help for this noob, much appreciated.
Here are my schemas:
bourbon:
'use strict';
var mongoose = require('mongoose'),
BourbonSchema = null;
module.exports = mongoose.model('Bourbon', {
name: {type: String, required: true},
blog: {type: String, required: true},
photo: {type: String, required: true, default:'http://aries-wineny.com/wp-content/uploads/2014/09/woodford-reserve.jpg'},
location: {type: String, required: true},
distillery: {type: String, required: true},
avgRating: {type: Number}
});
var Bourbon = mongoose.model('Bourbon', BourbonSchema);
module.exports = Bourbon;
comments:
'use strict';
var mongoose = require('mongoose');
module.exports = mongoose.model('Comment', {
bourbonId: {type: mongoose.Schema.ObjectId, ref: 'Bourbon'},
userId: {type: mongoose.Schema.ObjectId, ref: 'User'},
text: {type: String, required: true},
createdAt: {type: Date, required: true, default: Date.now},
rating : {type: Number, required: true},
votes: {type: Number, default: 0}
});
this is my find / get in the controller, which I tried piecing together from the referenced link, but is slopp now:
'use strict';
var Bourbon = require('../../../models/bourbon'),
Comment = require('../../../models/comment'),
DataStore = require('nedb'),
db = new DataStore(),
async = require('async');
module.exports = {
description: 'Get Bourbons',
notes: 'Get Bourbons',
tags: ['bourbons'],
handler: function(request, reply){
async.waterfall(
[
function(comment,callback){
async.series(
[
function(callback){
Bourbon.find({},function(err,results){
async.eachLimit(results,10,function(result,callback){
db.insert({
'bourbonId': result._id.toString(),
'location' : result.location,
'blog' : result.blog,
'distillery': result.distillery,
'name': result.name,
'avgRating': 0
},callback);
},callback);
});
},
function(callback){
Comment.aggregate(
[
{'$group':{
'_id': '$bourbonId',
'avgRating':{
'$avg':'$rating'
}
}}
],
function(err,results){
async.eachLimit(results,10,function(result,callback){
db.update(
{'bourbonId': result._id.toString()},
{'$set':{
'avgRating': result.avgRating
}
},
callback
);
},callback);
}
);
}
],
function(err) {
if (err) callback(err);
db.find({},{'_id': 0},callback);
}
);
}
],
function(err,results){
reply({results: results});
console.log('LOOOOOOOOOOOOOOOOK',JSON.stringify(results, undefined, 4));
process.exit();
});
}
};
Seems you have more to learn about callbacks and sequencing. This is all the code inside your request handler that you need. Of course changing to send the response when you see what is happening.
async.series(
[
// List out exiting collection with 0 average
function(callback) {
Bourbon.find({},function(err,results){
async.eachLimit(results,10,function(result,callback){
var plain = result.toObject()
plain.bourbonId = plain._id.toString();
plain.avgRating = 0;
delete plain._id;
db.insert(plain,callback); // next each iteration
},callback); // move to next in series
});
},
// Get aggregate results and update the items you just wrote
function(callback) {
Comment.aggregate(
[
{ '$group': {
'_id': '$bourbonId',
'avgRating':{ '$avg':'$rating' }
}}
],
function(err,results) {
async.eachLimit(results,10,function(result,callback){
db.update(
{ 'bourbonId': result._id.toString() },
{'$set': {'avgRating': result.avgRating } },
callback // next each iteration
);
},callback); // next in series "last"
}
);
}
],
// This is called when both in the series are complete
function(err) {
if (err) callback(err);
db.find({},{'_id': 0},function(err,docs) {
console.log( docs );
});
}
);
The aim here is:
Put 0 values in a hash table ( here using nedb ) for all items
Get aggregation results from the other collection
Update the copy of all items with those items that actually have a value
When all is done then you read back your hash table
Full working example:
var async = require('async'),
mongoose = require('mongoose'),
DataStore = require('nedb'),
db = new DataStore(),
Schema = mongoose.Schema;
var userSchema = new Schema({
"name": String
});
var ratingSchema = new Schema({
"bourbonId": { "type": Schema.Types.ObjectId, "ref": "Bourbon" },
"userId": { "type": Schema.Types.ObjectId, "ref": "User" },
"rating": { "type": Number, "required": true }
});
var bourbonSchema = new Schema({
"name": { "type": String, "required": true },
"blog": { "type": String, "required": true },
"photo": { "type": String, "required": true },
"ratings": [{ "type": Schema.Types.ObjectId, "ref": "Rating" }],
"rating": { "type": Number }
});
var User = mongoose.model( "User", userSchema ),
Rating = mongoose.model( "Rating", ratingSchema ),
Bourbon = mongoose.model( "Bourbon", bourbonSchema );
mongoose.connect("mongodb://localhost/bourbon");
async.waterfall(
[
function(callback) {
async.each([User,Rating,Bourbon],function(model,callback) {
model.remove({},callback);
},
function(err) {
callback(err);
});
},
function(callback) {
Bourbon.create({
"name": 'test',
"blog": 'test',
"photo": 'test'
},callback);
},
function(bourbon,callback) {
Bourbon.create({
"name": 'another',
"blog": 'another',
"photo": 'another'
},callback);
},
function(bourbon,callback) {
User.create({ "name": 'ted' },function(err,user) {
if (err) callback(err);
Rating.create({
"bourbonId": bourbon,
"userId": user,
"rating": 5
},function(err,rating1) {
callback(err,user,bourbon,rating1)
});
});
},
function(user,bourbon,rating1,callback) {
Rating.create({
"bourbonId": bourbon,
"userId": user,
"rating": 7
},function(err,rating2) {
callback(err,bourbon,rating1,rating2);
});
},
function(bourbon,rating1,rating2,callback) {
Bourbon.findById(bourbon.id,function(err,bourbon) {
bourbon.ratings.push(rating1,rating2);
bourbon.save(function(err,bourbon) {
callback(err)
});
});
},
function(callback) {
async.series(
[
function(callback) {
Bourbon.find({},function(err,results) {
if (err) callback(err);
async.eachLimit(results,10,function(result,callback) {
var plain = result.toObject();
plain.bourbonId = plain._id.toString();
plain.avgRating = 0;
delete plain._id;
db.insert(plain,callback);
},callback);
});
},
function(callback) {
Rating.aggregate(
[
{ "$group": {
"_id": "$bourbonId",
"avgRating": { "$avg": "$rating" }
}}
],
function(err,results) {
if (err) callback(err);
async.eachLimit(results,10,function(result,callback) {
db.update(
{ "bourbonId": result._id.toString() },
{ "$set": { "avgRating": result.avgRating } },
callback
);
},callback);
}
);
}
],
function(err) {
if (err) callback(err);
db.find({},{ '_id': 0 },callback);
}
);
}
],
function(err,results) {
if (err) throw err;
console.log( results );
mongoose.disconnect();
}
);
Returns results as expected:
[ { name: 'test',
blog: 'test',
photo: 'test',
__v: 0,
ratings: [],
bourbonId: '54c17bea8aa5f8c9161f5b6e',
avgRating: 0 },
{ name: 'another',
blog: 'another',
photo: 'another',
__v: 1,
ratings: [ [Object], [Object] ],
bourbonId: '54c17bea8aa5f8c9161f5b6f',
avgRating: 6 } ]
As far as I know, it's possible to sort populated docs with Mongoose (source).
I'm searching for a way to sort a query by one or more populated fields.
Consider this two Mongoose schemas :
var Wizard = new Schema({
name : { type: String }
, spells : { [{ type: Schema.ObjectId, ref: 'Spell' }] }
});
var Spell = new Schema({
name : { type: String }
, damages : { type: Number }
});
Sample JSON:
[{
name: 'Gandalf',
spells: [{
name: 'Fireball',
damages: 20
}]
}, {
name: 'Saruman',
spells: [{
name: 'Frozenball',
damages: 10
}]
}, {
name: 'Radagast',
spells: [{
name: 'Lightball',
damages: 15
}]
}]
I would like to sort those wizards by their spell damages, using something like :
WizardModel
.find({})
.populate('spells', myfields, myconditions, { sort: [['damages', 'asc']] })
// Should return in the right order: Saruman, Radagast, Gandalf
I'm actually doing those sorts by hands after querying and would like to optimize that.
You can explicitly specify only required parameters of populate method:
WizardModel
.find({})
.populate({path: 'spells', options: { sort: [['damages', 'asc']] }})
Have a look at http://mongoosejs.com/docs/api.html#document_Document-populate
Here is an example from a link above.
doc
.populate('company')
.populate({
path: 'notes',
match: /airline/,
select: 'text',
model: 'modelName'
options: opts
}, function (err, user) {
assert(doc._id == user._id) // the document itself is passed
})
Even though this is rather an old post, I'd like to share a solution through the MongoDB aggregation lookup pipeline
The important part is this:
{
$lookup: {
from: 'spells',
localField: 'spells',
foreignField:'_id',
as: 'spells'
}
},
{
$project: {
_id: 1,
name: 1,
// project the values from damages in the spells array in a new array called damages
damages: '$spells.damages',
spells: {
name: 1,
damages: 1
}
}
},
// take the maximum damage from the damages array
{
$project: {
_id: 1,
spells: 1,
name: 1,
maxDamage: {$max: '$damages'}
}
},
// do the sorting
{
$sort: {'maxDamage' : -1}
}
Find below a complete example
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/lotr');
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
let SpellSchema = new Schema({
name : { type: String },
damages : { type: Number }
});
let Spell = mongoose.model('Spell', SpellSchema);
let WizardSchema = new Schema({
name: { type: String },
spells: [{ type: Schema.Types.ObjectId, ref: 'Spell' }]
});
let Wizard = mongoose.model('Wizard', WizardSchema);
let fireball = new Spell({
name: 'Fireball',
damages: 20
});
let frozenball = new Spell({
name: 'Frozenball',
damages: 10
});
let lightball = new Spell({
name: 'Lightball',
damages: 15
});
let spells = [fireball, frozenball, lightball];
let wizards = [{
name: 'Gandalf',
spells:[fireball]
}, {
name: 'Saruman',
spells:[frozenball]
}, {
name: 'Radagast',
spells:[lightball]
}];
let aggregation = [
{
$match: {}
},
// find all spells in the spells collection related to wizards and fill populate into wizards.spells
{
$lookup: {
from: 'spells',
localField: 'spells',
foreignField:'_id',
as: 'spells'
}
},
{
$project: {
_id: 1,
name: 1,
// project the values from damages in the spells array in a new array called damages
damages: '$spells.damages',
spells: {
name: 1,
damages: 1
}
}
},
// take the maximum damage from the damages array
{
$project: {
_id: 1,
spells: 1,
name: 1,
maxDamage: {$max: '$damages'}
}
},
// do the sorting
{
$sort: {'maxDamage' : -1}
}
];
Spell.create(spells, (err, spells) => {
if (err) throw(err);
else {
Wizard.create(wizards, (err, wizards) =>{
if (err) throw(err);
else {
Wizard.aggregate(aggregation)
.exec((err, models) => {
if (err) throw(err);
else {
console.log(models[0]); // eslint-disable-line
console.log(models[1]); // eslint-disable-line
console.log(models[2]); // eslint-disable-line
Wizard.remove().exec(() => {
Spell.remove().exec(() => {
process.exit(0);
});
});
}
});
}
});
}
});
});
here's the sample of mongoose doc.
var PersonSchema = new Schema({
name: String,
band: String
});
var BandSchema = new Schema({
name: String
});
BandSchema.virtual('members', {
ref: 'Person', // The model to use
localField: 'name', // Find people where `localField`
foreignField: 'band', // is equal to `foreignField`
// If `justOne` is true, 'members' will be a single doc as opposed to
// an array. `justOne` is false by default.
justOne: false,
options: { sort: { name: -1 }, limit: 5 }
});