Why is my Mongoose schema missing one of its fields? - node.js

This is my schema:
var RegionSchema = new Schema({
"metadata": {
"type": String,
"name": String,
"children": [{
"name": String,
"type": String
}],
"parent": Schema.ObjectId
},
"data": [DataContainer]
});
This is a unit test I am writing, in which I store an instance of this object with some null values:
describe('Region with no data', function() {
it('Should save without error', function(done) {
var emptyRegion = new Region({
"metadata": {
"type": "City",
"name": "San Diego",
"children": [],
"parent": null
},
"data": []
});
emptyRegion.save(function(err, saved) {
console.log(saved)
if (err) throw err;
if (saved.metadata.name === "San Diego")
done();
})
});
});
However, when I try to print out what is saved, I get this:
{ __v: 0, _id: 551cd261cc55c5ff48c8150b, data: [] }
Why is my metadata object not saving? Even before the save call, emptyRegion looks just like that. Am I not defining my metadata correctly?

The annoying culprit is the type field within the metadata subdocument. Mongoose interprets that as meaning that metadata is of type String and has a bunch of irrelevant properties. Change your schema definition to the following and it should work:
var RegionSchema = new Schema({
"metadata": {
"type": {"type": String},
"name": String,
"children": [{
"name": String,
"type": {"type": String}
}],
"parent": Schema.ObjectId
},
"data": [DataContainer]
});
Alternatively, use a different name for your type fields.

Related

How to POST with Array inside Array Mongoose Schema

There are my mongoose schemas. I guess its ok. (https://mongoosejs.com/docs/subdocs.html)
const mongoose = require("mongoose");
const itemSchema = mongoose.Schema({
"itemNo": {
"type": "String"
}
});
const mySchema = mongoose.Schema({
"items":[itemSchema],
"title": {
"type": "String"
},
"data": {
"type": "String"
},
"pic": {
"type": "String"
},
"star": {
"type": "Boolean"
},
"category": {
"type": "String"
},
"date": {
"type": "Date"
},
});
module.exports = mongoose.model('dashboards', mySchema);
But im having trouble with post method. How can fix the code?
When i post my json, its returning with empty "items".
router.post("/", (req, res) => {
const post = new Model1({
title: req.body.title,
data: req.body.data,
pic: req.body.pic,
star: req.body.star,
category: req.body.category,
items: [req.body.items]
});
I edited my project like this. My problem is solved.
Here is my schemas.
const mongoose = require("mongoose");
const itemSchema = mongoose.Schema({
"itemNo": {
"type": "String"
},
});
const mySchema = mongoose.Schema({
"title": {
"type": "String"
},
"data": {
"type": "String"
},
"pic": {
"type": "Date"
},
"star": {
"type": "Boolean"
},
"category": {
"type": "String"
},
"items": [itemSchema]
});
module.exports = mongoose.model('dashboards', mySchema);
This is my post request.
router.post("/", (req, res) => {
const post = new Model1({
title: req.body.title,
data: req.body.data,
pic: req.body.pic,
star: req.body.star,
category: req.body.category,
items: req.body.items
});

How should I fetch data from another collection and join with the result

I have an endpoint which gives me a list of all Profiles available, now I have a Post Schema & Profile Schema, I want to add a list of posts that specific users have made to my result
Code present in endpoint
const profiles = await Profile.find()
.populate('user', [
'name',
'avatar'
])
Profile Schema
const ProfileSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
post: [],
........
Post Schema
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
text: {
type: String,
required: true
},
........
Response
[
{
"social": {
"youtube": "https://youtube.com/.",
"twitter": "https://twitter.com/.",
"facebook": "https://fb.com/."
},
"post": [], //This should populate
"skills": [
"HTML",
"CSS",
"PHP",
"Ruby"
],
"_id": "5ced6cb9e3f7485ee2cb0445",
"user": {
"_id": "5ced02551b60fe20afc72a32",
"name": "John abc",
"avatar": "//www.gravatar.com/avatar/1f9d9a9efc2f523b2f09629444632b5c?s=200&r=pg&d=mm"
},
"status": "Developer",
"experience": [
{
"current": true,
"_id": "5ceebb30bb0c667b85a94f97",
"from": "2010-08-09T18:30:00.000Z",
"description": "lorem ipasum"
}
],
"date": "2019-05-28T17:15:37.755Z",
"__v": 30,
"bio": "I am dev",
"education": [
{
"current": false,
"_id": "5cf0c1dc6b8dc33cd68be560",
"degree": "BE",
"from": "2005-07-09T18:30:00.000Z",
"to": "2010-03-03T18:30:00.000Z",
"description": "Got BE"
}
]
}
]
Expected output
[
{
"social": {
"youtube": "https://youtube.com/.",
"twitter": "https://twitter.com/.",
"facebook": "https://fb.com/."
},
"post": [
{_id:98as98djakjbkasd,
text:"This is post by xyz user"
},
{_id:234oijaoijd,
text:"This is another post by xyz user"
}
]
"skills": [
"HTML",
"CSS",
"PHP",
"Ruby"
],
"_id": "5ced6cb9e3f7485ee2cb0445",
"user": {
"_id": "5ced02551b60fe20afc72a32",
"name": "John abc",
"avatar": "//www.gravatar.com/avatar/1f9d9a9efc2f523b2f09629444632b5c?s=200&r=pg&d=mm"
},
.....
I want to populate posts done by the same user, what changes are needed to be done in endpoint code.
I am new to mongoose, upon searching for solutions I found aggregate could be useful but it cannot be used like .find().aggregate([...])
Trying to join in MongoDB would defeat the purpose of using MongoDB. As we first think about our use case then decide database and schema. You could however use DBref and write your own application code.
Another thing you can alter your schema into a single collection and use embedded document
It's always a suggestion of MongoDB that avoid join in our query!

How to add custom data to mongoose schema?

Suppose I have a very simple Schema like this:
const PlayerSchema = new Schema({
Region: {type: String},
Tier: {type: String},
Division: {type: String}
});
And further suppose that PlayerSchema lives in a MongoDB collection, where making a GET request to "/players" return a list of all the players in the collection:
router.get("/players", function(req, res){
DbSchemas.PlayerSchema.find({}).then(function(players){
res.send(players);
});
});
This is the response I get from making that GET request to "/players":
[
{
"Region": "North America",
"Tier": "Gold",
"Division": "III"
},
{
"Region": "Asia",
"Tier": "Platnium",
"Division": "IV"
}
]
However, suppose now I want to add some custom data to the PlayerSchema that are not in the database. I want the result returned to be something like this:
[
"code": 200,
"status": "OK",
"data": {
{
"Region": "North America",
"Tier": "Gold",
"Division": "III"
},
{
"Region": "Asia",
"Tier": "Platnium",
"Division": "IV"
}
]
Basically, I still want the MongoDB collection to store only the PlayerSchema (without the code and status), I would like to append the code:200 and status:OK myself if possible.
Here's what I tried. It doesn't work. I start by creating another schema:
const PlayerDataSchema = new Schema({
code: {type: Number},
status: {type: String},
data: {
type: [PlayerSchema]
}
});
Then, I tried to create an instance of PlayerDataSchema using the constructor, and assigning the PlayerSchema object to PlayerDataSchema.
router.get("/players", function(req, res){
DbSchemas.PlayerSchema.find({}).then(function(players){
var PlayerData = new DbSchemas.PlayerDataSchema({ ResponseCode:200 }, { ResponseStatus:"OK" }, {Players: players});
res.send(PlayerData);
});
});
This doesn't work and just gives me a TypeError: DBSchemas.PlayerDataSchema is not a constructor.
How do I add custom data into a schema?
You don't need to modify the schema to add fields to the response.
Your desired output isn't valid json:
[
"code": 200,
"status": "OK",
"data": {
{
"Region": "North America",
"Tier": "Gold",
"Division": "III"
},
{
"Region": "Asia",
"Tier": "Platnium",
"Division": "IV"
}
]
Arrays contain objects, and you're putting key-pairs in. That won't work.
That said, you just need to take the response and manipulate it with javascript to make it whatever you need it to be.
For example, if your retrieved data is this array:
players = [
{
"Region": "North America",
"Tier": "Gold",
"Division": "III"
},
{
"Region": "Asia",
"Tier": "Platnium",
"Division": "IV"
}
]
You can make another object to return like this:
result = {
code: 200,
status: "OK",
data: players
};
So your return value would be:
{
code: 200,
status: "OK",
data: [
{
"Region": "North America",
"Tier": "Gold",
"Division": "III"
},
{
"Region": "Asia",
"Tier": "Platnium",
"Division": "IV"
}
]
};
Which is an object with 3 keys, a number, a string, and an array.
I hope that sets you on the right course.

How can I make schema Given output using mongoose?

I have given my output for this how can I make schema.any one give example for this I have added my schema also
My output code:
$scope.countries = [{
"name": "India",
"states": [{
"name": "Maharashtra",
"cities": [{
"name": "Pune"
}, {
"name": "Mumbai"
}, {
"name": "Nagpur"
}, {
"name": "Akola"
}]
}, {
"name": "Madhya Pradesh",
"cities": [{
"name": "Indore"
}, {
"name": "Bhopal"
}, {
"name": "Jabalpur"
}]
}, {
"name": "Rajasthan",
"cities": [{
"name": "Jaipur"
}, {
"name": "Ajmer"
}, {
"name": "Jodhpur"
}]
}]
}, {
"name": "USA",
"states": [{
"name": "Alabama",
"cities": [{
"name": "Montgomery"
}, {
"name": "Birmingham"
}]
}, {
"name": "California",
"cities": [{
"name": "Sacramento"
}, {
"name": "Fremont"
}]
}, {
"name": "Illinois",
"cities": [{
"name": "Springfield"
}, {
"name": "Chicago"
}]
}]
}, {
"name": "Australia",
"states": [{
"name": "NewSouthWales",
"cities": [{
"name": "Sydney"
}]
}, {
"name": "Victoria",
"cities": [{
"name": "Melbourne"
}]
}]
}];
This is my routes:
app.route('/address')
.get(address.list)
.post(address.create);
Controller code:
/**
* Create a address
*/
exports.create = function(req, res) {
var address = new Address(req.body);
address.user = req.user;
address.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(address);
}
});
};
Schema code :
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var citySchema = {
name: {type:String, required: false}
};
citySchema = 'new Schema('+ citySchema +',{_id:false})';
var stateSchema = {
name: {type:String, required: false},
cities: [citySchema], default:[]
};
stateSchema = 'new Schema('+stateSchema +',{_id:false})';
var countrySchema = {
name: {type:String, required: false},
states: [stateSchema], default:[]
};
// dbObj is mongoose connection object
var collectionObj = dbObj.model('countries', countrySchema);
i have updated my routes and controller schema .how can i change to inser that object pls give some suggestion ?
Please try with following schema :-
var citySchema = {
name: {type:String, required: false}
};
citySchema = 'new Schema('+ citySchema +',{_id:false})';
var stateSchema = {
name: {type:String, required: false},
cities: [citySchema], default:[]
};
stateSchema = 'new Schema('+stateSchema +',{_id:false})';
var countrySchema = {
name: {type:String, required: false},
states: [stateSchema], default:[]
};
// dbObj is mongoose connection object
var collectionObj = dbObj.model('countries', countrySchema);
Now if you want to insert any single country data into db please go through with following procedure-
// Let us assume that we need to insert following data first
var data = {
"name": "India",
"states": [{
"name": "Maharashtra",
"cities": [{
"name": "Pune"
}, {
"name": "Mumbai"
}, {
"name": "Nagpur"
}, {
"name": "Akola"
}]
}, {
"name": "Madhya Pradesh",
"cities": [{
"name": "Indore"
}, {
"name": "Bhopal"
}, {
"name": "Jabalpur"
}]
}, {
"name": "Rajasthan",
"cities": [{
"name": "Jaipur"
}, {
"name": "Ajmer"
}, {
"name": "Jodhpur"
}]
}]
};
// add country
var insertObj = {
"name": "India",
"states": []
}
countryModel.create(insertObj, function (err, job) {
cb(err, job);
});
// add states
var states = [{
"name": "Maharashtra",
"cities": []
}, {
"name": "Madhya Pradesh",
"cities": []
}, {
"name": "Rajasthan",
"cities": []
}];
var stateCond = {"name": "India"};
var stateUpdate = {$push: {states: states}};
var stateOpts = {};
countryModel.findOneAndUpdate(stateCond, stateUpdate, stateOpts, function (err, resp) {
cb(err, resp);
});
// Now if you want to add "Maharastra" Cities
var cities = [{
"name": "Pune"
}, {
"name": "Mumbai"
}, {
"name": "Nagpur"
}, {
"name": "Akola"
}]
var cityCond = {"name": "India", "states.name": "Maharashtra"};
var cityUpdate = {$push: {cities: cities}};
var cityOpts = {};
countryModel.findOneAndUpdate(cityCond, cityUpdate, cityOpts, function (err, resp) {
cb(err, resp);
});
// Now same insertion query need to be run for "Madhya Pradesh" and "Rajasthan"
Thanks

Using Mongoose JS to get array of pointer values for document, and expand return

What I am trying to do is the following.
I have objects that could live in multiple documents, and although I am not sure if this is best practice, I am using their ObjectId as pointers.
Document A
{
"_id": {
"$oid": "51a02dade4b02780aeee5ab7"
},
"title": "My Document A",
"artifacts": [
"51a81d8ee4b084336fea2d33",
"asdfsdfe4b084336fea2d33"
]
}
Document B
{
"_id": {
"$oid": "51a02dade4b02780aeee5ab7"
},
"title": "My Document A",
"artifacts": [
"51a81d8ee4b084336fea2d33",
"123454b084336fea2d33"
]
}
The individual artifact looks something like. If this artifact changes then there is no need to update the documents that it lives in:
{
"_id": {
"$oid": "51a81d8ee4b084336fea2d33"
},
"title": "Artifact A",
"media": {
"player": "video",
"source": "http://www.youtube.com/watch?v=12334456"
}
}
What I'd like to do, is get an expanded list of all the artifacts shown in either doc A or doc B in an array something like:
[{
"_id": {
"$oid": "51a81d8ee4b084336fea2d33"
},
"title": "Artifact A",
"media": {
"player": "video",
"source": "http://www.youtube.com/watch?v=12334456"
}
},
{
"_id": {
"$oid": "123455e4b084336fea2d33"
},
"title": "Artifact B",
"media": {
"player": "video",
"source": "http://www.youtube.com/watch?v=12334456"
}
}]
The way I have done it in the past is by POSTing from client a list of Ids and then using
{_id: { $in: userQuestArray} }
but if i am constantly posting back to node from the client it seems a bit inefficient. Especially if the array I am posting is hundreds of items long.
Mongoose provide you a feature population which exactly does the same thing you are looking for http://mongoosejs.com/docs/populate.html. In your case what you need to do is
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var tempSchema = Schema({
title : String,
artifacts : [{ type: Schema.Types.ObjectId, ref: 'Artifacts' }]
});
var artifactsSchema = Schema({
title : String,
media : { player: String, source: String, }
});
var tempModel = mongoose.model('Temp', tempSchema);
var artifactsModel = mongoose.model('Artifacts', artifactsSchema);
Now whenever artifacts documents gets created you need to push that in respective temp dcoument artifacts array as shown in mongoose documentation. You can retrive it like that
tempModel
.find(query)
.populate('artifacts')
.exec(function (err, results) {
if (err)
console.log(err);
console.log(results);
})
//results contains data in form shown below
[{
"_id": {
"$oid": "51a02dade4b02780aeee5ab7"
},
"title": "My Document A",
"artifacts": [{
"_id": {
"$oid": "51a81d8ee4b084336fea2d33"
},
"title": "Artifact A",
"media": {
"player": "video",
"source": "http://www.youtube.com/watch?v=12334456"
}
},
{
"_id": {
"$oid": "123455e4b084336fea2d33"
},
"title": "Artifact B",
"media": {
"player": "video",
"source": "http://www.youtube.com/watch?v=12334456"
}
}]
}]

Resources