Postman only posts to mongoose nested level 1 - javascript

I'm trying to test a post to a mongoose schema that has nested fields, but I'm only able to level 1 and the first field in level 2. For example:
I have a network model that can contain multiple ip addresses and multiple subnets. When I place the query in to Postman it allows me to create multiple ip addresses and multiple subnets (great) but I can't define a type field for example?
Mongoose Schema:
var mongoose = require('mongoose'), Schema = mongoose.Schema, ObjectId = mongoose.Schema.ObjectId;
var networkSchema = module.exports = mongoose.model('Network', {
network_id:ObjectId,
location: String,
hostname: String,
device: String,
model: String,
ipAddress: [ipaddressSchema],
subnets: [subnetSchema],
iosVersion: String,
softwareImage: String,
serialNumber: String,
});
var ipaddressSchema = Schema ({
ipAddress: String,
type: String,
});
var subnetSchema = Schema ({
range: String,
type: String,
});
Controller:
var Network = require('../models/network');
module.exports.create = function (req, res) {
var network = new Network(req.body);
network.save(function (err, result) {
res.json(result);
});
}
module.exports.list = function (req, res) {
Network.find({}, function (err, results) {
res.json(results);
});
}
Postman Query:
Postman Result:
I would like:
{
"__v": 0,
"location": "London Office",
"hostname": "lon-asa-01",
"device": "Switch-MLS",
"model": "Cisco 3750",
"softwareImage": "1.2",
"serialNumber": "123456",
"_id": "5510495c1d40ef965d7d1cec",
"subnets":[
["range" : "10.0.100.0/24", "type" : "Client" ],
["range" : "10.0.101.0/24", "type" : "Server" ],
],
"ipAddress": [
["ipAddress" : "10.0.100.1", "type" : "Inside" ],
["ipAddress" : "10.0.101.254", "type" : "Outside" ],
]
}

Ok, here you go:
First of all, your schema should look like this:
var networkSchema = module.exports = mongoose.model('Network', {
network_id: ObjectId,
location: String,
hostname: String,
device: String,
model: String,
ipAddress: [{type: ObjectId, ref: 'IpadressModelName'}],
subnets: [{type: ObjectId, ref: 'SubnetModelName'}],
iosVersion: String,
softwareImage: String,
serialNumber: String,
});
In your controller you have to insert first the entities on which your network relies on so you will have an _id to provide to the network model as reference:
module.exports.create = function (req, res) {
var network = new Network(req.body);
var ipAddress = [],
ipIds = [];
req.body.ipAddress.forEach(function(ip){
ipAddress.push(new IpadressModelName(ip));
});
var subnets = [],
subnetsIds = [];
req.body.subnets.forEach(function(sn){
subnets.push(new SubnetModelName(sn));
});
IpadressModelName.create(ipAddress, function () {
// args[0] should be the error
if (args[0]) {
throw args[0]
}else{
for(var i=1; i<args.length; i++ )
ipIds.push(args[i]._id);
}
SubnetModelName.create(subnets, function () {
// args[0] should be the error
if (args[0]) {
throw args[0]
}else{
for(var i=1; i<args.length; i++ )
subnetsIds.push(args[i]._id);
}
network.ipAddress = ipIds;
network.subnets = subnetsIds;
network.save(function (err, result) {
res.json(result);
});
});
});
}
Finally post data as raw JSON:
{
"location": "London Office",
"hostname": "lon-asa-01",
"device": "Switch-MLS",
"model": "Cisco 3750",
"softwareImage": "1.2",
"serialNumber": "123456",
"subnets":[
{"range" : "10.0.100.0/24", "type" : "Client" },
{"range" : "10.0.101.0/24", "type" : "Server" }
],
"ipAddress": [
{"ipAddress" : "10.0.100.1", "type" : "Inside" },
{"ipAddress" : "10.0.101.254", "type" : "Outside" }
]
}
The code in this example is just for demonstrating a approach you can use and it is not conforming to the best practices.

Related

How can i iterate mongoose returned documents array in loop using mongoose?

I have a node.js(express based) server in which i have a function which returns all users. Here is the function.
export async function findAllUser() {
let users = await User.find({}).exec()
return users
}
In my node.js applicaiton i have two models(schema) of Users and Referrals like this .
var User = mongoose.model(
"users",
new Schema({
first_name: String,
last_name: String,
name: String,
email: String,
password: String,
roleId: { type: Number, default: 0 },
country: String,
token: String,
createdAt: String,
updatedAt: String,
tempToken: String,
verificationCode: String,
fbUserId: String,
isFbUser: { type: Boolean, default: false },
isActive: { type: Boolean, default: true },
isEmailVerified: { type: Boolean, default: false },
rememberme: Boolean,
}, {
toJSON: { virtuals: true },
toObject: { virtuals: true }
})
);
User.virtual("referrals", {
ref: "referralLinks",
foreignField: "userId",
localField: "_id"
});
export var ReferralLink = mongoose.model(
"referralLinks",
new Schema({
referral_link: String,
referral_code: String,
isLink: Number,
offer_name: String,
offer_desc: String,
user_email: String,
companyId: { type: Schema.Types.ObjectId, ref: 'companies' },
addedByAdmin: { type: Boolean, default: true },
number_of_clicks: Number,
referral_country: String,
link_status: String,
categoryId: { type: Schema.Types.ObjectId, ref: 'categories' },
number_of_clicks: { type: Number, default: 0 },
createdAt: String,
updatedAt: String,
userId: { type: Schema.Types.ObjectId, ref: 'users' }
})
);
I have my separate api.route.js file in which i have get all users route like this
router.get("/", log, getAllUsers);
And i my api.controller.js file i have getAllUsers like this
export async function getAllUsers(req, res) {
try {
let Users = await findAllUser()
if (Users) {
generateResponse(true, "All Users fetched", Users, res)
} else {
generateResponse(false, "No Users found", null, res)
}
} catch (err) {
generateResponse(false, 'Error occured, 404 not found!', err, res)
}
}
And in my api.handler.js file i have findAllUser function like this
export async function findAllUser() {
let users = await User.find({}).populate("referrals").exec()
return users
}
Single user can have more than one Referrals. But unfortunately i don't have 'Referrals' reference _id in Users document. Now, i want to get all users with their respective Referrals
I am getting all users correctly but for each user i also want to fetch all their respective referrals. So for that i definitely can't use for or forEach loop because of async nature of mongoose find. So what should i use instead of for or forEach loop?
My desired results
results = [
{
first_name : "Fahad",
last_name : "subzwari",
email : "fahadsubzwari#gmail.com",
password : "***",
referrals : [
{
//referral object 1
},
{
//referral object 2 ...
}
]
},
{
first_name : "Alex",
last_name : "Hales",
email : "alex#gmail.com",
password : "***",
referrals : [
{
//referral object 1
},
{
//referral object 2 ...
},
{
//referral object 3 ...
}
]
},
]
To be able to access referrals from user you need to use virtual populate.
So your userSchema must be like this:
const userSchema = new Schema(
{
first_name: String,
last_name: String,
name: String,
email: String,
password: String,
roleId: { type: Number, default: 0 },
country: String,
token: String,
createdAt: String,
updatedAt: String,
tempToken: String,
verificationCode: String,
fbUserId: String,
isFbUser: { type: Boolean, default: false },
isActive: { type: Boolean, default: true },
isEmailVerified: { type: Boolean, default: false },
rememberme: Boolean
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true }
}
);
// Virtual populate
userSchema.virtual("referrals", {
ref: "referralLinks",
foreignField: "userId",
localField: "_id"
});
var User = mongoose.model("users", userSchema);
And now you can use this route to access referrals from users:
router.get("/", async (req, res) => {
const result = await User.find({}).populate("referrals");
res.send(result);
});
The result will be like this: ( I excluded some fields for simplicity)
[
{
"_id": "5dd6819201419f5930d02334",
"name": "User 1",
"email": "user1#gmail.com",
"password": "123123",
"__v": 0,
"referrals": [
{
"_id": "5dd6829831b95a6b2cd58fca",
"referral_link": "referral_link 1",
"userId": "5dd6819201419f5930d02334",
"__v": 0
},
{
"_id": "5dd682a031b95a6b2cd58fcb",
"referral_link": "referral_link 2",
"userId": "5dd6819201419f5930d02334",
"__v": 0
}
],
"id": "5dd6819201419f5930d02334"
},
{
"_id": "5dd681a101419f5930d02335",
"name": "User 2",
"email": "user2#gmail.com",
"password": "123123",
"__v": 0,
"referrals": [
{
"_id": "5dd682a731b95a6b2cd58fcc",
"referral_link": "referral_link 3",
"userId": "5dd681a101419f5930d02335",
"__v": 0
}
],
"id": "5dd681a101419f5930d02335"
}
]
UPDATE:
Here is the steps for your project setup:
api.handler.js:
exports.findAllUser = async function() {
console.log("api handler inside");
let users = await User.find({})
.populate("referrals")
.exec();
console.log("in handler: ", users);
return users;
};
api.controller.js:
const handler = require("./api.handler");
exports.getAllUsers = async function(req, res) {
console.log("userController.getAllUsers");
try {
let Users = await handler.findAllUser();
if (Users) {
return res.send(Users);
generateResponse(true, "All Users fetched", Users, res);
} else {
generateResponse(false, "No Users found", null, res);
}
} catch (err) {
generateResponse(false, "Error occured, 404 not found!", err, res);
}
};
api.route.js
const apiController = require("../controllers/api.controller");
router.get("/", log, apiController.getAllUsers);
You say "i don't have 'Referrals' reference _id in Users" so I assume you have a reference to the user in the Referrals schema?
Otherwise, with no way to link them you are lost at sea I'm afraid... :-(
If you do then you would do it in a separate query:
const userIds = users.map(user => user._id);
const referrals = await Referrals.find({ userId: { $in: userIds } })
The $in operator will grab any field where the user id is included in the array.
EDIT: In response to your update - yes the above should work fine. Then you can do what you want with them e.g. map the referrals to the user objects, or use them individually etc. etc.
EDIT2: Yep this is the way. At this point you have an array of users and an array of referrals so you just need to put them together.
users.map(user => ({
// add props from user obj
...user,
// add all referrals that with matching userId
referrals: referrals.filter(referral => referral.userId === user._id)
}))
Remember that as you are dealing with asynchronous calls and promises so you will either need to use the async/await keywords, or parse the results in the promise callback.

Mongoose: Schema for nested Json and store it (Node.js)

I'm pretty new to js and mongoose and I've ended up with a nested JSON.
var standardmessage = {
"id": "352",
"name": "a name",
"type": "a type",
"message":
{
"messagetype": "default message",
"timestamp": "35235326326",
"messagestatus": "running"
}
}
Now I tried to define a schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var messageSchema = new Schema({
id: Number,
name: Schema.Types.Mixed,
type: Schema.Types.Mixed,
message:
{
messagetype: String,
timestamp: Number,
messagestatus: String
}
}, {collection: 'test'});
var testmodel = mongoose.model('messagemodel', messageSchema,'test');
module.exports = testmodel;
Finally I tried to store it through Mongoose into MongoDB:
var Message = new testmodel({standardmessage});
Message.save(function (err) {
if (err) console.log(err);
});
Either my schema is wrong and i need multiple schemas to store it correctly or sth. else is wrong. But in my database it only get's stored like this:
{ "_id" : ObjectID("xxxxxxxxxxx"), "__v" : 0}
Is it possible to define one Schema to store this nested JSON? If yes, how?
If not, how do I manage to store it correctly?
Why does it only store an ObjectID?
Thanks in advance, appreciating every kind of help and sorry if my question is stupid as im new to this.
Update:
var messageSchema = new Schema({
id: Number,
name: Schema.Types.Mixed,
type: Schema.Types.Mixed,
message: [message]
}, {collection: 'test'});
var message = new Schema({
"messagetype": "default message",
"timestamp": "35235326326",
"messagestatus": "running"
})
Then it gets stored like this { "_id" : ObjectID("xxxxxxxxxxx"), "message" : [], "__v" : 0}
For a nested JSON, you can do something like this:
var mongoose =require('mongoose');
var Schema = mongoose.Schema;
var standardmessage = new Schema({
id: Number,
name: String,
type: String,
message: {
messageType: String,
timestamp: Number,
messagestatus: String
}
});
If the nested block is a list then you can do this:
var mongoose =require('mongoose');
var Schema = mongoose.Schema;
var msg = new Schema({
messageType: String,
timestamp: Number,
messagestatus: String
});
var standardmessage = new Schema({
id: Number,
name: String,
type: String,
message: [msg]
});

mongoose findall return data from a different model

In users.js:
var mongoose = require('mongoose');
var User = mongoose.model('user', {
username: {
type: String,
required: true,
unique: true,
lowercase: true,
},
tasks: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Tasks',
}],
});
module.exports = User;
I then add a newUser named user1 and save to mongo.
The mongo doc looks like:
{
"_id" : ObjectId("574fb94f6a1e7d1826c16058"),
"username" : "user1",
"tasks" : [ ],
"__v" : 0
}
then try to fetch the document and it works fine in this handler:
In handlerA.js:
var User = require('../models/users.js');
module.exports.getUser = function(req, res){
User.findOne({username: "user1"}, function(err, data){
if(err){
console.log('getUser err', err);
res.send('ERROR')
} else {
console.log('getUser fx success = ', err, data);
res.send(data)
}
});
};
The result of the console.log:
getUser fx success = null { tasks: [], __v: 0, username: 'user1', _id: 574fb94f6a1e7d1826c16058 }
but same code fails in this other handler in a separate file.
In handlerB.js:
var User = require('../models/users.js');
module.exports.addStuff = function(req, res){
User.findOne({username: "user1"}, function(err, data){
if(err){
console.log('addStuff err', err);
res.send('ERROR')
} else {
console.log('addStuff fx success =', err, data);
res.send(data)
}
});
};
The result of the console.log:
addStuff fx success null null
Tried....and Failed....
I also tried this other solution from this question: Mongoose query return null
Mongoose pluralizes model names so it's running find on the "blogposts" collection instead of "blogpost". That said, your query in the mongo shell is on the "blogmodel" collection. In that case:
var BlogModel = mongoose.Model("BlogModel", ..)
or pass the collection name as the third param:
var BlogModel = mongoose.model("BlogPost", schema, "blogmodel")
This solution results in handlerA.js returning a null document as well as handlerB.js.
Thanks for your time. Much appreciated.
ADDENDUM.
I ran a find({}) under both the User and the Tasks models in handlerB.js
The returned document IN BOTH cases is based on the Tasks model.
see console.logs below for User.find({}) and Tasks.find({})
the err is the null value then the data.
How badly have I broken things? How can a Model.find return data that is not even in the model?
User.find({},funtion(err, data) ____________________
console.log of err then data
null
[ { subtasks: [],
team: [ [Object] ],
__v: 0,
maintask: '1',
_id: 574fce63d744cba421f750c1
},
{ subtasks: [],
team: [ [Object] ],
__v: 0,
maintask: '2',
_id: 574fce65d744cba421f750c2
}
]
Tasks.find({},function(err, data) ___________________
console.log of err then data
null
[ { subtasks: [],
team: [ [Object] ],
__v: 0,
maintask: '1',
_id: 574fce63d744cba421f750c1 },
{ subtasks: [],
team: [ [Object] ],
__v: 0,
maintask: '2',
_id: 574fce65d744cba421f750c2
},
]
This is the Tasks model...
tasks.js
var mongoose = require('mongoose');
var subtaskSchema = new mongoose.Schema({
subtask: {
type: String,
},
team: {
type: Array,
'defualt': [],
},
done: {
type: Boolean,
'defualt': false,
},
});
var Tasks = mongoose.model('tasks', {
maintask: {
type: String,
},
subtasks: {
type: [subtaskSchema],
},
team: {
type: Array,
'defualt': [],
},
done: {
type: Boolean,
'defualt': false,
},
});
module.exports = Tasks;
The mongoose docs suggest to define a model like so, did you try this?
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
var Tank = mongoose.model('Tank', schema);

How to populate a group in mongoose

I have this in my mongoose schema...with some group...
'use strict';
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
var clientSchema = new mongoose.Schema({
name : { type: String },
offerings : [{ type: String }],
cscPersonnel : {
salesExec : { type: Schema.Types.ObjectId, ref: 'User' },
accountGM : { type: Schema.Types.ObjectId, ref: 'User' },
},
},
netPromoterScore : { type: Number }
});
module.exports = mongoose.model('clients', clientSchema);
I tried to populate reff dis way...I have also populated in ref (user as {path:'cscPersonnel'})
function getOneById(id){
var deferred = Q.defer();
console.log("im in get by id" +id);
model
.findOne({ _id: id })
.populate({path:'cscPersonnel'})//one way
/* 'cscPersonnel salesExec', //second way
'cscPersonnel accountGM', */
.exec(function (err, item) {
if(err) {
console.log(err);
deferred.reject(err);
}
else
console.log(item);
deferred.resolve(item);
});
return deferred.promise;
} // gentOneById method ends
but unfortunatly ended up with this error!!!!
CastError: Cast to ObjectId failed for value "[object Object]" at path "_id"
{
"message": "Cast to ObjectId failed for value \"[object Object]\" at path \"_id\"",
"name": "CastError",
"type": "ObjectId",
"value": {
"salesExec": "56cf5f09245f8a240b30693b",
"accountGM": "56cf5f09245f8a240b30693b"
},
"path": "_id"
}
how to make it solve this issue.... do help , thanks in advance
Please try this one
model
.findOne({ _id: id })
.populate({path: 'cscPersonnel.salesExec'})
.populate({path: 'cscPersonnel.accountGM'})
.exec(function (err, item) {

How to find a sub-document using Mongoose?

I'm trying to get a sub-document in my User collection using mongoose. I followed the Mongoose Sub Document on its official website. It's written that:
Each document has an _id. DocumentArrays have a special id method for looking up a document by its _id.
var doc = parent.children.id(id);
Here is my code:
exports.editAccount = function(req, res) {
var user = new User(req.user);
var newAccount = new Account(req.body);
console.log("Account:" + newAccount._id); // Gave me 53bf93d518254f880c000009
var account = user.accounts.id(newAccount._id);
console.log("Account" + account); // Never been printed
};
The console.log("Account" + account); has never been printed. I don't know what happen. I tried many different ways, however, still can't figure it out. Any help would be appreciated.
User collection:
{
"__v" : 1,
"_id" : ObjectId("53bcf3e6fbf5adf10c000001"),
"accounts" : [
{
"accountId" : "123456789",
"type" : "Saving account",
"balance" : 100,
"_id" : ObjectId("53bf93d518254f880c000009")
}
]
}
I
Not too sure how you have defined your Schema or basically even model instances, but really all you need is this:
var accountSchema = new Schema({
"accountId": String,
"type": { "type": String, "enum": ["Saving Account", "Checking Account"] },
"balance": { "type": Number, "default": 0 }
]);
var userSchema = new Schema({
"accounts": [accountSchema]
]);
var User = mongoose.model( "User", userSchema );
Then when you want to add an account to the User you just do, presuming you have input that matches the first variable declaration:
var input = {
"accountId": "123456789",
"type": "Savings Account",
};
User.findByIdAndUpdate(
userId,
{ "$push": { "accounts": input } },
function(err,user) {
// work with result in here
}
);
That does bypass things like validation and other hooks, but is more efficient in communicating with MongoDB.
If you really need the validation and/or other features then you and using a .find() variant and issuing a .save() method.
User.findById(userId,function(err,user) {
if (err) throw err; // or handle better
user.accounts.push( input );
user.save(function(err, user) {
// more handling
});
]);
And to modify the document then you are doing much the same. Either by the most efficient MongoDB way:
var input = {
accountId: "123456789",
amount: 100
};
User.findOneAndUpdate(
{ "_id": userId, "accounts.accountId": input.accountId },
{ "$inc": { "accounts.$.balance": input.amount } },
function(err,user) {
// handle result
}
);
Or again where you need the Mongoose hooks and or validation to apply:
User.findById(userId,function(err,user) {
if (err) throw err; // or handle otherwise
user.accounts.forEach(function(account) {
if ( account.accountId === input.accountId )
account.balance += input.balance;
});
user.save(function(err,user) {
// handle things
});
);
Remember that these things are "arrays", and you can either handle them the MongoDB way or the JavaScript way. It just depends on where you choose to "validate" your input.
More code to illustrate where the usage is not correct:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/child');
var accountSchema = new Schema({
"accountId": String,
"type": { "type": String },
"balance": { "type": Number, "default": 0 }
});
var userSchema = new Schema({
"accounts": [accountSchema]
});
var User = mongoose.model( "User", userSchema );
async.waterfall([
function(callback) {
User.create({},function(err,user) {
if (err) throw err;
console.log(
"Created:\n%s\n",
JSON.stringify( user, undefined, 4 )
);
callback(null,user);
});
},
function(user,callback) {
var account = user.accounts.create({
"accountId": "123456789",
"type": "Savings"
});
console.log(
"Account is:\n%s\n",
JSON.stringify( account, undefined, 4 )
);
console.log(
"User is still:\n%s\n",
JSON.stringify( user, undefined, 4 )
);
user.accounts.push( account );
console.log(
"User Changed:\n%s\n",
JSON.stringify( user, undefined, 4 )
);
User.findById(user.id,function(err,saved) {
if (err) throw err;
console.log(
"Persisted is still:\n%s\n",
saved
);
user.save(function(err,user) {
if (err) throw err;
callback(null,user,account);
});
});
},
function(user,account,callback) {
User.findById(user.id,function(err,saved) {
if (err) throw err;
console.log(
"Persisted is now:\n%s\n",
saved
);
var item = user.accounts.id(account.id);
console.log(
"Item is:\n%s\n",
item
);
callback();
});
}
],function(err) {
process.exit();
});
Results:
Created:
{
"__v": 0,
"_id": "53c08ab51083d1fe3852becc",
"accounts": []
}
Account is:
{
"accountId": "123456789",
"type": "Savings",
"_id": "53c08ab51083d1fe3852becd",
"balance": 0
}
User is still:
{
"__v": 0,
"_id": "53c08ab51083d1fe3852becc",
"accounts": []
}
User Changed:
{
"__v": 0,
"_id": "53c08ab51083d1fe3852becc",
"accounts": [
{
"accountId": "123456789",
"type": "Savings",
"_id": "53c08ab51083d1fe3852becd",
"balance": 0
}
]
}
Persisted is still:
{ _id: 53c08ab51083d1fe3852becc, __v: 0, accounts: [] }
Persisted is now:
{ _id: 53c08ab51083d1fe3852becc,
__v: 1,
accounts:
[ { accountId: '123456789',
type: 'Savings',
_id: 53c08ab51083d1fe3852becd,
balance: 0 } ] }
Item is:
{ accountId: '123456789',
type: 'Savings',
_id: 53c08ab51083d1fe3852becd,
balance: 0 }

Categories