Getting error during the time of inserting the query on database - node.js

I am Facing the error at the time of insert the query.
Error is "db.collection.insert is not a function"
My database schema is like this
'use strict';
var mongoose = require('mongoose');
//Schema
var ABCSchema = mongoose.Schema({
sequenceid: {
type: Number
},
A: {
type: Array,
default: []
},
B: {
type: Array,
default: []
},
C: {
type: Array,
default: []
},
D: {
type: Array,
default: []
}
});
var ABC = module.exports = mongoose.model('ABC', ABCSchema);
Now I want to enter the data which looks like this.
It's just a sample by which you people can understand that how I can Store the value.
{
"_id" : ObjectId("5a2e2eb9104cce1b58385620"),
"sequenceid": 1,
"A" : [
{
"apple" : "red",
"count" : 24
}
],
"B" : [],
"C" : [],
"D" : [],
"__v" : 0
}
Now what I am trying to code is like this
ABC.insert({'sequenceid': 1, 'A': {'apple': 'red', 'count': 24}}, function(error, data){
console.log(data);
});

As #Manjeet Thakur pointed out what you are trying to insert at "A" is and object and not an Array
Change it to array
{
"A": [{
"apple": "red",
"count": 24
}],
"sequenceid": 1
}
Also you need to instantiate your model and save it
var abc = new ABC({'sequenceid': 1, 'A': [{'apple': 'red', 'count': 24}]});
abc.save()
//or
ABC.create({'sequenceid': 1, 'A': [{'apple': 'red', 'count': 24}]}, function (err, small) {
//if (err) return throw err;
// saved!
})

'use strict';
var mongoose = require('mongoose');
//Schema
var ABCSchema = mongoose.Schema({
sequenceid: {
type: Number
},
A: {
type: Array,
default: []
},
B: {
type: Array,
default: []
},
C: {
type: Array,
default: []
},
D: {
type: Array,
default: []
}
});
var ABC = module.exports = mongoose.model('ABC', ABCSchema);
// here now collection is ABC (name of collection)
ABC.insert({'sequenceid': 1, 'A': [{'apple': 'red', 'count': 24}] }, function(error, data){
console.log(data);
});

Related

Parsing posted object array, Express

I need to parse data with Express from form:
invoiceRouter.post('/', async (req,res) => {
console.log(req.body);
let invoice = new Invoice();
invoice = req.body;
invoice.status = 0;
//save
res.redirect('/invoices');
});
When I log, the array of objects is read as list of values:
{
createdDate: '2021-10-15',
invoiceRows: [ 'Title3', '2', 'Title2', '3' ]
}
But it can not read the invoiceRows as array of 2, therefore I am struggling to parse it into array for saving it.
When I set the extended: false, I can see following result from req.body:
[Object: null prototype] {
createdDate: '2021-10-15',
'invoiceRows[0].productTitle': 'Title2',
'invoiceRows[0].unitPrice': '2',
'invoiceRows[1].productTitle': 'Title3',
'invoiceRows[1].unitPrice': '2'
}
The schema I am using:
const invoiceSchema = new mongoose.Schema({
createdDate: {
type: Date,
required: true
},
status: {
type: Number,
required: true
},
invoiceRows: [{
productTitle: String,
unitPrice: Number
}]
});
Question: what am I doing wrong, in order to get array of objects from req.body inside parent object?
In your req.body you should be receiving like bellow (As per your model schema). Make your front end to send data like bellow.
{
createdDate: '2021-10-15',
invoiceRows: [ { productTitle :'Title1', unitPrice : 2}, { productTitle :'Title2', unitPrice : 3} ]
}

How to populate documents with unlimited nested levels using mongoose

I'm designing a web application that manages organizational structure for parent and child companies. There are two types of companies: 1- Main company, 2 -Subsidiary company.The company can belong only to one company but can have a few child companies. My mongoose Schema looks like this:
var companySchema = new mongoose.Schema({
companyName: {
type: String,
required: true
},
estimatedAnnualEarnings: {
type: Number,
required: true
},
companyChildren: [{type: mongoose.Schema.Types.ObjectId, ref: 'Company'}],
companyType: {type: String, enum: ['Main', 'Subsidiary']}
})
module.exports = mongoose.model('Company', companySchema);
I store all my companies in one collection and each company has an array with references to its child companies. Then I want to display all companies as a tree(on client side). I want query all Main companies that populates their children and children populate their children and so on,with unlimited nesting level. How can I do that? Or maybe you know better approach. Also I need ability to view,add,edit,delete any company.
Now I have this:
router.get('/companies', function(req, res) {
Company.find({companyType: 'Main'}).populate({path: 'companyChildren'}).exec(function(err, list) {
if(err) {
console.log(err);
} else {
res.send(list);
}
})
});
But it populates only one nested level.
I appreciate any help
You can do this in latest Mongoose releases. No plugins required:
const async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
const uri = 'mongodb://localhost/test',
options = { use: MongoClient };
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
function autoPopulateSubs(next) {
this.populate('subs');
next();
}
const companySchema = new Schema({
name: String,
subs: [{ type: Schema.Types.ObjectId, ref: 'Company' }]
});
companySchema
.pre('findOne', autoPopulateSubs)
.pre('find', autoPopulateSubs);
const Company = mongoose.model('Company', companySchema);
function log(data) {
console.log(JSON.stringify(data, undefined, 2))
}
async.series(
[
(callback) => mongoose.connect(uri,options,callback),
(callback) =>
async.each(mongoose.models,(model,callback) =>
model.remove({},callback),callback),
(callback) =>
async.waterfall(
[5,4,3,2,1].map( name =>
( name === 5 ) ?
(callback) => Company.create({ name },callback) :
(child,callback) =>
Company.create({ name, subs: [child] },callback)
),
callback
),
(callback) =>
Company.findOne({ name: 1 })
.exec((err,company) => {
if (err) callback(err);
log(company);
callback();
})
],
(err) => {
if (err) throw err;
mongoose.disconnect();
}
)
Or a more modern Promise version with async/await:
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.set('debug',true);
mongoose.Promise = global.Promise;
const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };
const companySchema = new Schema({
name: String,
subs: [{ type: Schema.Types.ObjectId, ref: 'Company' }]
});
function autoPopulateSubs(next) {
this.populate('subs');
next();
}
companySchema
.pre('findOne', autoPopulateSubs)
.pre('find', autoPopulateSubs);
const Company = mongoose.model('Company', companySchema);
function log(data) {
console.log(JSON.stringify(data, undefined, 2))
}
(async function() {
try {
const conn = await mongoose.connect(uri,options);
// Clean data
await Promise.all(
Object.keys(conn.models).map(m => conn.models[m].remove({}))
);
// Create data
await [5,4,3,2,1].reduce((acc,name) =>
(name === 5) ? acc.then( () => Company.create({ name }) )
: acc.then( child => Company.create({ name, subs: [child] }) ),
Promise.resolve()
);
// Fetch and populate
let company = await Company.findOne({ name: 1 });
log(company);
} catch(e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})()
Produces:
{
"_id": "595f7a773b80d3114d236a8b",
"name": "1",
"__v": 0,
"subs": [
{
"_id": "595f7a773b80d3114d236a8a",
"name": "2",
"__v": 0,
"subs": [
{
"_id": "595f7a773b80d3114d236a89",
"name": "3",
"__v": 0,
"subs": [
{
"_id": "595f7a773b80d3114d236a88",
"name": "4",
"__v": 0,
"subs": [
{
"_id": "595f7a773b80d3114d236a87",
"name": "5",
"__v": 0,
"subs": []
}
]
}
]
}
]
}
]
}
Note that the async parts are not actually required at all and are just here for setting up the data for demonstration. It's the .pre() hooks that allow this to actually happen as we "chain" each .populate() which actually calls either .find() or .findOne() under the hood to another .populate() call.
So this:
function autoPopulateSubs(next) {
this.populate('subs');
next();
}
Is the part being invoked that is actually doing the work.
All done with "middleware hooks".
Data State
To make it clear, this is the data in the collection which is set up. It's just references pointing to each subsidiary in plain flat documents:
{
"_id" : ObjectId("595f7a773b80d3114d236a87"),
"name" : "5",
"subs" : [ ],
"__v" : 0
}
{
"_id" : ObjectId("595f7a773b80d3114d236a88"),
"name" : "4",
"subs" : [
ObjectId("595f7a773b80d3114d236a87")
],
"__v" : 0
}
{
"_id" : ObjectId("595f7a773b80d3114d236a89"),
"name" : "3",
"subs" : [
ObjectId("595f7a773b80d3114d236a88")
],
"__v" : 0
}
{
"_id" : ObjectId("595f7a773b80d3114d236a8a"),
"name" : "2",
"subs" : [
ObjectId("595f7a773b80d3114d236a89")
],
"__v" : 0
}
{
"_id" : ObjectId("595f7a773b80d3114d236a8b"),
"name" : "1",
"subs" : [
ObjectId("595f7a773b80d3114d236a8a")
],
"__v" : 0
}
I think a simpler approach would be to track the parent since that is unique instead of tracking an array of children which could get messy. There is a nifty module called mongoose-tree built just for this:
var tree = require('mongoose-tree');
var CompanySchema = new mongoose.Schema({
companyName: {
type: String,
required: true
},
estimatedAnnualEarnings: {
type: Number,
required: true
},
companyType: {type: String, enum: ['Main', 'Subsidiary']}
})
CompanySchema.plugin(tree);
module.exports = mongoose.model('Company', CompanySchema);
Set some test data:
var comp1 = new CompanySchema({name:'Company 1'});
var comp2 = new CompanySchema({name:'Company 2'});
var comp3 = new CompanySchema({name:'Company 3'});
comp3.parent = comp2;
comp2.parent = comp1;
comp1.save(function() {
comp2.save(function() {
comp3.save();
});
});
Then use mongoose-tree to build a function that can get either the ancestors or children:
router.get('/company/:name/:action', function(req, res) {
var name = req.params.name;
var action = req.params.action;
Company.find({name: name}, function(err, comp){
//typical error handling omitted for brevity
if (action == 'ancestors'){
comp.getAncestors(function(err, companies) {
// companies is an array
res.send(companies);
});
}else if (action == 'children'){
comp.getChildren(function(err, companies) {
res.send(companies);
});
}
});
});

Mapping other collection by same schema name on Mongoose

Engine Collection
var EngineSchema = new mongoose.Schema({
name: String,
GF2: String,
GF3: String,
GF4: String,
ll98: String,
ll01: String,
ll04: String
});
Oil Collection
var OilSchema = new mongoose.Schema({
name: String,
GF2: String,
GF3: String,
GF4: String,
ll98: String,
ll01: String,
ll04: String
});
I made simple
Engine DB
{ _id: 57d9604b7ecbc0029a3aad3c,
name: 'N54 B30A',
ll01: '1',
ll01fe: '1',
ll04: '1',
__v: 0 }
OilDB
[ { _id: 57d9614265e6c402a2c09990, name: 'EDGE', ll04: '1', __v: 0 },
{ _id: 57d98e12acc05505cfd15aae,
name: 'SYNTEC',
GF2: '1',
GF3: '1',
GF4: '1',
__v: 0 } ]
If I have the N54 B30A than It needs classification about ll98, ll01, ll04
EDGE Product only one about classification ll04
totally I choose the 'N54 B30A' that has ll04 classification so I want to appear something that has the ll04 classification
'N54 B30A' -> ll04
'EDGE' -> ll04
ll04 mapping?
Select N54 B30A -> appear EDGE
My Code Simple but It did't execute
Engine.findOne({name: 'N54 B30A'}, {_id: 0, name: 0, __v: 0}, function(err, engine) {
var result = Object.keys(engine.toObject());//[ 'll01', 'll01fe', 'll04' ]
Oil.findOne({result[2] : 1},function (err, oil) {
console.log(oil)
});
})
More Question
I want to search many kind atrribute(ll01, ll01fe, ll04) such as
findOne({$or:{ll01:1},{ll01le:1},{ll04:1}},function...)
but I don't know how to add one item like {ll01 : 1} than add {ll01le:1} and {ll04:1}
I tried coding
My Code
Engine.findOne({name: 'N54 B30A'}, {_id: 0, name: 0, __v: 0}, function (err, engine) {
var result = Object.keys(engine.toObject());//[ 'll01', 'll01fe', 'll04' ]
var Json = [];
result.forEach(function (item) {
var code = {};
code[item] =1;
Json.push(code);
});
console.log(Json);
Oil.find({$or: Json}, function (err, oil) {
console.log(oil)
});
})
I'm not useful javascript so I made by only my thinking. is this right?
You cannot assign a value to JSON as {result[2] : 1}. Change your code to this
Engine.findOne({name: 'N54 B30A'}, {_id: 0, name: 0, __v: 0}, function(err, engine) {
var result = Object.keys(engine.toObject());//[ 'll01', 'll01fe', 'll04' ]
var oilFindQuery = {};
oilFindQuery[result[2]] = 1;
//or query
var orQuery = [];
result.forEach(function (item) {
var queryItem = {};
queryItem[item] = 1
orQuery.push(queryItem);
});
//oilFindQuery = {$or: orQuery};
Oil.findOne(oilFindQuery, function (err, oil) {
console.log(oil)
});
})

Mongoose .find() with conditions returns no result

I am working on a MEAN Stack app with a pre-existing MongoDB collection and if I define conditions for .find() no results were returned while it works without conditions.
Here is the code from my model file:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var mainSchema = new Schema({
id: Number,
x: Number,
y: Number,
prio: Number,
type0: String,
type1: String,
type2: String,
width: Number,
height: Number,
text1: String,
text2: String,
size1: Number,
font: String,
color1: String,
color2: String,
links: String,
peers: String
}, { collection: 'main' });
mainSchema.statics = {
load: function(l, t, r, b, cb){
console.log(l, t, r, b);
return this.find({
x: { $gt: l, $lt: r },
y: { $gt: t, $lt: b }
}).exec(cb);
}
};
module.exports = mongoose.model('main', mainSchema);
This is one object from the output without conditions:
[
{
"_id": "577faf952a7c33f2fe44b282",
"id": 4,
"x": 50944,
"y": 54995,
"prio": 1,
"type0": "a",
"type1": "a",
"type2": "a",
"width": 100,
"height": 100,
"text1": "Chemie",
"text2": "",
"size1": 48,
"font": "f1_a ",
"color1": "#000000",
"color2": "#bfdeff",
"links": "14,53445,57328,12,#ff3d3d,k&13,54744,53904,12,#8c8c86,k&12,52557,51870,12,#f2ff12,k&11,51172,49743,12,#2312ff,k&10,48270,47335,12,#49fe6e,k&",
"peers": "1"
}
]
Here is the code that calls the load methode:
var mongoose = require('mongoose');
var main = require('../models/main');
exports.load = function(req, res){
main.load(parseInt(req.query.l), parseInt(req.query.t), parseInt(req.query.r), parseInt(req.query.b), function(err, data) {
res.jsonp(data);
});
};
Problem solved!
Despite the output all data were stored as strings instead of int within MongoDB.
I just copied the JSON output (where the types are correct) to a file and imported it to MongoDB, now the code works fine.

Updating Reference Along With Other Values Mongoose

Here is a schema that I am working on.
var testSchema = mongoose.Schema({
userCreated : {
type : mongoose.Schema.Types.ObjectId,
ref : "User"
},
points : {type: Number, default: 0},
numVotes : {type: Number, default: 0},
createdAt : Date,
updatedAt : Date,
}, { timestamps : true });
Now, I am trying to write a function that will increment two fields on this document (points and numVotes, as well as an additional points field that exists on the user schema.
Here is my attempt.
testSchema.statics.incrementTest = function(id, ...) {
this.findByIdAndUpdate(id, {$inc : {
points : 5,
numVotes : 1,
'userCreated.points' : 5
}}).exec();
}
Now, this code that I have written does not work. However, when I comment out the 'userCreated.points' : 5 line, the other two fields do increment as expected. My question is, what is the best way using mongoose to update the fields on a document and the fields on a subdocument at the same time?
The data here is contained in different collections, so no single update statement is able to increment counters in both at the same time.
In order to get a consistent view you are going to need to "chain" your update statements and use the return results of each to build the response.
Depending on your needs you can either use a Promise with this:
testSchema.statics.incrementTest = function(id) {
var self = this;
return new Promise(function(resolve,reject) {
self.findByIdAndUpdate(
id,
{
"$inc": {
"points": 5,
"numVotes": 1
}
},
{ "new": true }
).then(function(test) {
var userModel = test.schema.path("userCreated").options.ref;
mongoose.model(userModel).findByIdAndUpdate(
test.userCreated,
{ "$inc": { "points": 5 } },
{ "new": true }
).then(function(user) {
test.userCreated = user;
resolve(test);
})
}).catch(reject)
})
};
Which you can then invoke on your model:
Test.incrementTest("56fe279d363ce91765d9e39e").then(function(test) {
console.log(JSON.stringify(test,undefined,2));
}).catch(function(err) {
throw err;
})
Or you can use async.waterfall from the async library if that suits you better:
testSchema.statics.incrementTest = function(id,callback) {
var self = this;
async.waterfall(
[
function(callback) {
self.findByIdAndUpdate(
id,
{
"$inc": {
"points": 5,
"numVotes": 1
}
},
{ "new": true },
callback
)
},
function(err,test) {
if (err) callback(err);
var userModel = test.schema.path("userCreated").options.ref;
mongoose.model(userModel).findByIdAndUpdate(
test.userCreated,
{ "$inc": { "points": 5 } },
{ "new": true },
function(err,user) {
if ( typeof(user) !== "undefined" )
test.userCreated = user;
callback(err,test);
}
);
}
],
callback
);
};
Which has a similar usage:
Test.incrementTest("56fe279d363ce91765d9e39e",function(err,test) {
if (err) throw err;
console.log(JSON.stringify(test,undefined,2));
})
Both should be giving you a result back that shows the incremented data in both objects for both collections:
{ points: 5,
numVotes: 1,
__v: 0,
userCreated: { points: 5, __v: 0, _id: 56ff1aa6dba6d13e798fc894 },
createdAt: Sat Apr 02 2016 12:04:38 GMT+1100 (AEDT),
updatedAt: Sat Apr 02 2016 12:04:38 GMT+1100 (AEDT),
_id: 56fe279d363ce91765d9e39e }

Resources