Create a Schema object in Mongoose/Handlebars with custom keys/values - node.js

I want to create a form to input custom keys and values of an object in an mongo/mongoose schema to eventually see in a handlebars view. See example to better explain. Any help would be great. :)
Mongoose/Mongodb Schema:
var docketSchema = new Schema({
staff: [{ String: String, String: String }]
});
Handlebars input view:
<div class="form-group">
<input value="{{input.staffkey1}}">
<input value="{{input.staffvalue1}}">
</div>
<div class="form-group">
<input value="{{input.staffkey2}}">
<input value="{{input.staffvalue2}}">
</div>

the reason to use mongoose is usually to ensure that your documents have some known keys and to validate new objects so they conform to your schema.
If you explicitly don't want your objects to have the same keys use the schema-type Mixed - http://mongoosejs.com/docs/schematypes.html:
var docketSchema = new Schema({
staff: [{}]
});

You can add strict: false to your schema to add fields to your schema which are not defined.
var docketSchema = new Schema({
//
}, {strict: false});
Nevertheless it is always better to define your fields.

Related

How to update a record in mongo db using node js

I have created a simple signup and login using node js and mongoDb. I can successfully do signup and login and now I want to add some more data to the user model after logging in from the secret page. How can I do that?
This is my user model and I want to add some text to user.text field after loggin in:
var mongoose = require("mongoose");
var UserSchema = mongoose.Schema({
username: String,
password: String,
text:String
});
module.exports = mongoose.model("User", UserSchema);
This is my view page (i.e., the secret page)
<h1>Hi, <%= user.username %></h1>
<form action="/birthday" method="post">
<input type="text" name="text">
<button type="submit">Update database</button>
</form>
The text should be shown here after updating.
Thanks!
You need to make an API on the node process to send the data to. I suggest you take a look at stuff like Express.js and google about REST API:s.

How to label HTML for saving nested objects in Mongoose?

I have a model that looks like this:
const recipeSchema = new Schema({
title: { type: String , required: true},
description: { type: String , required: true},
steps:[{
text:{type:String},
ingredients:{type:String}
}]});
Using a bodyparser, I'm able to save data by simply tagging them in the name attribute of the HTML form. Like below:
<div class="input-field">
<textarea id="title" name="title" placeholder="Enter title here"></textarea>
<label for="title">Title</label>
</div>
This method works well for the first 2 fields (title and description), but I'm stuck on how to label them for the steps field. How would I make the code understand which input fields are for step.text and which are for steps.ingredient? And create an array of objects?
Figured it out. For anybody else who may stumble across this post, here's how you do it.
Basically you need to refer to the object in the array as (per the example above) in the following format:
step[0][text]
I couldn't find it anywhere in the documentation, but finally got it from this link:
http://www.thiscodeworks.com/how-to-save-input-from-html-form-to-json-file-using-body-parser-html-nodejs/5c44c4722178800014d5f127
How are you passing your data to the html page? I think using a view engine like EJS solves your problem better. It allows you to pass your data to a view, and then inject the data directly into your html elements.

How can I access an object from a Mongoose Schema through the form?

I have this mongoose schema:
var mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
let userSchema = new mongoose.Schema({
username:
{type: String,
unique: true
},
password: String,
privileges:
{
region: [Number],
read: [Boolean],
write: [Boolean],
edit: [Boolean],
delete: [Boolean]
}
});
userSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", userSchema);
and I'm using this with the following form:
<form action="/register" method="POST">
<input type="text" name="username"><br/>
<input type="password" name="password"><br/>
<input type="text" name="privileges.region"><br/>
<input type="text" name="privileges.read"><br/>
<input type="text" name="privileges.write"><br/>
<input type="text" name="privileges.edit"><br/>
<input type="text" name="privileges.delete"><br/>
<button>Submit</button>
</form>
I suppose the name is okay because privileges is an object, so every property should be accessed with the dot notation. If it's not, please let me know.
req.body looks like this:
When I try to console.log(req.body.privileges.region) or any other property, I get undefined. How should I access one of the privileges objects properties? Thanks.
The keys for the dictionary coming back on the request are actually the strings: 'privileges.region', 'privileges.delete', etc. So you must access them as
req.body['privileges.region']
People will generally write a helper function that handles this sort of notation to map it back their original model. Or they might do the mapping when the form is submitted in the browser in order to get the data in the shape you really want it:
{username
permissions:{region, ...}
...
}

How do I update a specific document from a form through mongoose?

Struggling with this problem because I'm missing some fundamentals I think, but after hours looking through the docs I think I need some help :)
I have a (simplified) collection as so:
const ExampleSchema= new Schema ({
Word: String,
Difficulty: String,
)};
Which I am succesfully displaying on a page as so:
<% ExampleSchemas.forEach(exampleschema=> { %>
<p><%= exampleschema.word %></p>
<p style="display: none" name="ExampleSchemaID" value="<%= ExampleSchema._id %>"</p>
<% }) %>
For each word I have a form below, I would like the user to be able to select easy, ok or hard and for this to set the value in the DB.
<form method="PUT">
<button formaction="/review/feedback/easy">Easy</button>
<button formaction="/review/feedback/ok">Ok</button>
<button formaction="/review/feedback/hard">Hard</button>
/form>
I have played around with a route like this to no avail
router.put("/review/feedback/easy", function (req,res){
var ID = req.body.ExampleSchemaID;
ExampleSchema.findByIdAndUpdate(
req.params.ExampleSchema._id,
req.Difficulty= easy);
The further issue is that I would like to display x number of these documents to the user, therefore I need a route that gets only that specific word.
router.put("/review/feedback/easy", function (req,res){
var ID = req.body.ExampleSchemaID;
ExampleSchema.findByIdAndUpdate({"_id": req.params.ExampleSchema._id},{"Difficulty": "3"});
but please not your difficulty is a number, so why not use a number instead:
const ExampleSchema= new Schema ({
Word: String,
Difficulty: Number,
)};
router.put("/review/feedback/easy", function (req,res){
var ID = req.body.ExampleSchemaID;
ExampleSchema.findByIdAndUpdate({"_id": req.params.ExampleSchema._id},{"Difficulty": 3});

Model is created but can't update with Express, Mongoose, and NodeJS

Alright so I'm having a problem with updating a model. I can create a Document and it works just fine but when I try to update, I get an error.
/Users/User/Sites/project/app.js:182
a.features.kids = req.body.a.features.kids;
^
TypeError: Cannot read property 'kids' of undefined
The model looks like this:
Affiliate = new Schema({
'name': String,
'address': String,
'features': {
'kids': { type: Boolean, default: false },
}
});
My form fields looks like this. They are used for both creating and updating with extra fields added for updating:
<input type="text" name="a[name]" id="a[name]" />
<input type="text" name="a[address]" id="a[address]" />
<input <% if (a.features.kids) { %>checked <% }; %>type="checkbox" name="a[features.kids]" id="a[features.kids]" />
Code for creating a new item. This works fine and all the information is added properly:
var a = new Affiliate(req.body.a);
a.save(function() {
res.redirect('/admin');
});
Broken code for updating an item:
Affiliate.findOne({ _id: req.params.id}, function(err, a) {
if (!a) return next(new NotFound('Affiliate not found'));
a.name = req.body.a.name;
a.address = req.body.a.address;
a.features.open_gym = req.body.a.features.kids;
a.save(function(err) {
res.redirect('/admin');
});
});
Yeah, I think the express bodyParser is probably not interpreting a[features.kids] the way you expect. You can access the field with req.body.a['features.kids'] since it's not interpreting that embedded period. Try naming your <input> a[features][kids] and see if that parses into the object structure you are expecting.

Resources