Recently I have started building my own RESTful API using the MEAN stack. So far, so good. Yesterday I bumped into a small issue, which I have been trying to solve, but no successful results have been seen until now...
I have a Mongoose Schema which looks like this:
const hotelSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
stars: {
type: Number,
min: 0,
max: 5,
"default": 0
},
services: [String],
description: {
type: String,
"default": "No description"
},
photos: [String],
currency: {
type: String,
"default": "Not specified"
},
reviews: [reviewSchema],
rooms: [roomSchema],
location: {
address: {
type: String,
"default": "Not specified"
},
// Always store coordinates longitude E/W, latitude N/S order
coordinates: {
type: [Number],
index: '2dsphere'
}
}
});
And this is how I create the model instance:
Hotel
.create({
name: req.body.name,
description: req.body.description,
stars: parseInt(req.body.stars, 10),
services: _splitArray(req.body.services),
photos: _splitArray(req.body.photos),
currency: req.body.currency,
location: {
address: req.body.address,
coordinates:[
parseFloat(req.body.lng),
parseFloat(req.body.lat)
]
}
Everything works perfect and as expected with a small detail. I am using Advanced Rest Client to make the POST request. It can be seen below:
Request with Rest Client
And this is what I get as a response:
Response from Rest Client
So the problem is that, if I do not enter an address, I would like to see the default value as it can be seen in the schema - "Not specified". Unfortunately, I cannot achieve this.
Can you please help me?
Solved!
Actually it seems that it did work correctly. When I make a GET request to fetch the newly created hotel by id, it actually returns it as I would like to, with "address" set to "Not specified".
The fact that after creating the hotel with Model.create() function, the callback that is returned contains the hotel, but without "address" being "Not specified".
I tried the request with Postman as well, the result is the same - no address set.
But anyway, I see that it actually works. I will try to find why the returned object in the callback is not complete though....
Related
I have been creating a movie booking app and I'm new to developing web apps. I am wondering on how to create a model for the same. For my condition, a movie can be showed in different locations. So I have given a location array in the movie model. I would also be able to sort based on locations. So I have created a location schema and a movie schema and referred the location schema inside movie schema. I'm giving the code snippet below.
Movie Schema
const movieSchema = new Schema ({
name: {
type: String,
required: true
},
language: {
type: String,
required: true
},
format : {
type: String,
enum: ["2D", "3D"],
required: true,
default:"2D"
},
rating : {
type: Number
},
location: [locationSchema]
})
Location Schema
const locationSchema = new Schema({
name: {
type: String,
}
});
I have created a post method to create a movie record in the database with express.
Post Method
const router=express.Router();
const {Movie}=require ('../models/movie');
const {Location}=require('../models/locations')
router.post('/', function (req,res) {
let body= req.body;
let movie = new Movie (body)
movie.save().then(function (movie) {
res.send(movie)
}).catch (function(err) {
res.send(err)
})
})
I have created the object as shown below to post from postman tool.
First Post Request
{
"name":"Frozen 2",
"language":"English",
"rating":4,
"location":[{
"name":"Chennai"
}, {
"name":"Bangalore"
}]
}
Another Post Request
{
"name":"Aladdin",
"language":"English",
"rating":4,
"location":[{
"name":"Bangalore"
}]
}
My first post request goes fine. But when adding a different movie entry, I am getting the "E11000 duplicate key error collection" for location as the location already exists. I dont know how to proceed further.
database noob here using MongoDB, in my program, I have users, and the core of my program are these roadmaps that I display. So, each user can create roadmaps, save others roadmaps, blah blah... Each user has a field named savedRoadmaps and createdRoadmaps which should store the roadmaps. My question is, should I just store the roadmap _ids in the savedRoadmap and createdRoadmaps field or the entire roadmap?
I am asking this because it feels like saving just the _id of the roadmaps can save storage, but it might not come in handy when I have to fetch the data of the user first, then fetch the roadmap using the roadmap ID in the user's savedRoadmap/createdRoadmap field, versus just fetching the user and the savedRoadmap field will already have the roadmap in there.
And btw, is there any sweet and brief database design read out there, please direct me to some if you know any!
For a user, I want it to have a name, email, password, description ofcourse, and also savedRoadmaps and createdRoadmaps. A user can create unlimited roadmaps and also save as much as he or she wants. For a roadmap, I want it to have a name, category, time_completion, author, date, and a roadmap object which will contain the actual json string that I will use d3 to display. Here's my User and Roadmap Schema right now:
const RoadmapSchema = new Schema({
author: {
type: String,
require: false
},
name: {
type: String,
require: true
},
category: {
type: String,
require: true
},
time_completion: {
type: Number,
require: true
},
date: {
type: Date,
default: Date.now
},
roadmap: {
type: "object",
require: true
}
});
and User Schema:
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
savedRoadmap: {
type: "object",
default: []
},
createdRoadmap: {
type: "object",
default: []
}
});
My question is, inside of the savedRoadmap and createdRoadmap fields of the User schema, should I include just the _id of a roadmap, or should I include the entire json string which represents the roadmap?
There are 3 different data-modeling techniques you can use to design your roadmaps system based on the cardinality of the relationship between users and roadmaps.
In general you need to de-normalize your data model based on the queries that are expected from your application:
One to Few: Embed the N side if the cardinality is one-to-few and there is no need to access the embedded object outside the context of the parent object
One to Many: Use an array of references to the N-side objects if the cardinality is one-to-many or if the N-side objects should stand alone for any reasons
One-to-Squillions: Use a reference to the One-side in the N-side objects if the cardinality is one-to-squillions
And btw, is there any sweet and brief database design read out there,
please direct me to some if you know any!
Rules of Thumb for MongoDB Schema Design: Part 1
I am currently working on a RESTful API, and I am trying to reference the users schema in the courses document such that, when a POST request gets sent to the route of the course, a course is created in the DB and has as one of its fields a reference to the user that created it. However, for the life of me, I cannot figure out why the "user" field is not appearing when I post. There seem to be quite a few of these questions here on Stack so I may just be adding to the pile, but I tried their solutions and they did not work for me
var mongoose = require('mongoose')
var Schema = mongoose.Schema
var userSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
emailAddress: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
var CourseSchema = new Schema({
user: {type: Schema.Types.ObjectId, ref: 'User'}, //FOR some reason this is not showing up on any courses created using the
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
estimatedTime: {
type: String
},
materialsNeeded: {
type: String
}
});
var User = mongoose.model('User', userSchema);
var Course = mongoose.model('Course', CourseSchema);
module.exports = {Course, User};
Do you see anything in here that would preclude the user field from appearing when a new course is created?
I have attached some screenshots to further explain.
This first image is a screen of the currently authenticated user credentials (fake data obviously). This is the user that is sending the POST request for the new course. I would expect his information to be attached to the course (see screenshot 3)
This image shows the body of the request that is sent. You can see that the key-value pairs match what is in the CourseSchema. I would expect that the "user" field would be created once the POST request is sent.
This last image is some dummy data that is the expected result.
Thanks all for taking a look at this!
User field will not be automatically added to the course document. You have to manually set the user field in the request body itself or while creating a course.
Example of the course body to be sent:-
{
user: "userId",
title: "test",
description: "test",
estimatedTime: "test",
materialsNeeded: 1
}
Also, the result of this will not include the whole user document as you have mentioned in the expected result. It will only return the userId. However, while accessing the course you can populate the user field to get the whole user document. Example for the same
Course.find({...query}).populate("user")
I need help with loopback framework.
I have two models: Post and Media.
Examples:
Media
{
id: ObjectId("...a1"),
type: "gif",
path: "some/folder"
},
{
id: ObjectId("...a2"),
type: "mp4",
path: "some/folder"
},
Post
{
id: ObjectId("...b1"),
title: "Apollo 13",
content: [
{
mediaId: ObjectId("...a1"),
header: "header-1",
description: "descr-1"
},
{
mediaId: ObjectId("...a2"),
header: "header-2",
description: "descr-2"
}
]
},
{
id: ObjectId("...b2"),
title: "2 seconds to Moon",
content: [
{
mediaId: ObjectId("...a1"),
header: "header-3",
description: "descr-3"
},
]
}
As you can guess I'm going to use MongoDb. I want to describe a relation between this two models, but not sure how to do it in the right way.
If I had only array of mediaIds, I'd make it through referenceMany. Now it's look more like embedsMany, but embeds many what?
I even tried to make something like MediaItem model and give it transient datasource. But I didn't make it works right with rest APIs.
At final I want to get one or many posts with including media data such as type and path fields.
Any thoughts?
Probably you should use HasManyThrough relation (http://loopback.io/doc/en/lb2/HasManyThrough-relations.html) and then include filter (http://loopback.io/doc/en/lb2/Include-filter.html)
I use Ember Data 1.13.4.
I have a model with some embedded records, let's say they look like this:
var Partner = DS.Model.extend({
name: DS.attr(),
addresses: DS.hasMany('address', { async: false } ),
});
var Address = DS.Model.extend({
type: DS.attr(),
zip: DS.attr(),
city: DS.attr(),
street: DS.attr()
});
The API sends back the Address records embedded in the Partner records. Example response:
{
"partners": [
{
"id": 47,
"name": "Johnny",
"addresses": [
{
"id": 7,
"type": "MAIN",
"zip": "1234",
"city": "City-X",
"street": "6. Nowhere"
}
],
},
]
}
The problem is that type on the Address model is just a normal property, but Ember Data wants it to be the type of the embedded model, and I get this assertion message:
Error: No model was found for 'MAIN'
Where 'MAIN' is the content of the type property.
I can't change how the API sends back data, I need to adapt to it.
How do I do this?
Edit: Important detail which I forgot to include the first time.
The API has a /partners/search endpoint, which I access with a direct ajax request, then I (supposedly) need to call this.store.pushMany('partner', this.store.normalize('partner', response.partners)); And this is when the No model was found for 'MAIN' is raised.
Your { partners: { addresses: [ ... ] } } is returning an embedded data, but because you are providing an object with id and type ember-data is understanding that the api returns an polymorphic association. And trying to find a model called MAIN, but since it does't exist Error: No model was found for 'MAIN' is raised.
In order to tell ember-data that your relationship is embedded you need to override the PartnerSerializer and include the DS.EmbeddedRecordsMixin.
App.ApplicationAdapter= DS.RESTAdapter;
App.ApplicationSerializer = DS.RESTSerializer;
App.PartnerSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
addresses: { embedded: 'always' }
}
})
A live demo of this sample running http://emberjs.jsbin.com/nufofehota/1/edit?html,js,output