HasMany with JunctionTable findAllJoin not serializing junction table attributes - node.js

So I have a User model which is connected to projects via a junction table. This junction table has some additional attributes like allow_read which I want to pass back in my response.
request.user.getProjects({
where : { do_sync : true, allow_read : true },
}).success(function(projects) {
// send proper response
response.jsonp(projects);
}).error(function(err) {
// send error response
response.status(500).jsonp(err);
});
In this code block 'allow_read' works properly and projects[0].user_project returns the additional attributes from the User_Project model. The problem is when 'projects' get serialized the user_project object disappears. projects[0].values also does not contain a user_project property even though projects[0].user_project does exist.
My question is if there is anyway for sequelize to automatically stringify both the projects and their junction table attributes without manually building that object myself?

Related

Sending the same PUT request multiple times creates more entries in the database

As far as I know, with PUT one can create a resource if it doesn't exist or it is going to replace the old one with a new one.
I want to create a resource and being able to update it, not create more resources, using Node.js/Express and MongoDB.
So, I wrote this code:
app.put('/entries/:entry_id/type', (req, res) => {
const entry = new Entry (req.body);
entry.save();
res.end();
})
in Postman there is a PUT request, having the url: localhost:5000/entries/2/type
After sending it once, it creates an entry in the dabatase. All good!
But let's try to send the same request again. Now there are 2 entries in the database. I would expect to be one, because the same request was sent.
In the database they have the same data, same schema but they do have an extra field,
"_id":{"$oid":"5e8909e60c606c002axxxxxx"},, which is has the last character different.
Why are there created more entries of the same data while I was expecting to have only one entry in the database?
Mongo automatically creates a default index named _id on every collection when it is created. If you insert a Document into a collection without specifying an _id it will generate a new ObjectId as the _id field.
To get around this you can use findOneAndUpdate with upsert:
Entry.findOneAndUpdate({ entry_id: req.params.entry_id }, { <content> }, { upsert: true })
However this will update the document if it exists already instead of creating a new one. If you further wish to not change the Document at all if it already exists, then you can surround your <content> with $setOnInsert.

Why is the object value not changing?

I am trying to pull a Post object from my MongoDB. This Post has an author field, which is an ObjectID referencing who authored the blog post. Once I fetch the blog post, I want to fetch the Author's username and replace the ID in the post object before sending it out to as a response to clients.
When running the code, the correct Post shows when I log it, and the correct Username is shown when it is fetched, but I can never modify the object itself.
BlogController.getPost(id, (error, result) => {
if (error) res.send({success:false, message:error})
else {
var post = result
AuthController.getUserByID(post.author, (error, resultNested) => {
if (error) res.send({success:false, message:error})
else {
post.author = resultNested.username
console.log(post)
console.log(resultNested)
res.send({success:true, message:post})
}
})
}
})
I would include the console log outputs to show you the structure of the objects and that the values I am trying to modify xist, but the new StackOverflow UI makes inputting code even more of a pain in the ass than the past. Somehow...
I expect for the post object to have it's authorfield modified, but the author field remains an ObjectID.
I would suggest storing the name of the author in the post model as a start. MongoDB is referred to as a 'Document Based' DB and I therefore like to think of each record in a collection as a standalone 'document'.
I can understand the logic of the relational model you are trying to implement, but since MongoDB stores data in JSON format - one could argue that there is some room for redundancy.
I would recommend...
post{
author : string;
.
.
.
relUser : string;
}
Where the relUser field will be the id of the user that posted the blog entry and we store the author/username in the author field. In this way you simplify the number of calls you need to make, by getting more info per single call.

Node, Mongoose: Remove json element from query result with delete

I get this strange behavior. Here's the thing: I make a database query and want to delete an element of the json returned by the query. So this doesn't seem to work (i.e. the element is not deleted),
var user=json;
delete user.element;
while this works
var user={element:json.element,blement:'stuff'}
delete user.element;
I think what you are referring to as JSON is actually a Mongoose document object given the tags you added to your question. Since that object is attached to it's "schema", you may have rules in there such as a "required" field or such that are interfering with the operation you are trying to do.
In order to get a raw form of the Object back, simply use the .toObject() method on the document result:
Model.findOne({ _id: id}, function(err,doc) {
var raw = doc.toObject();
delete raw.element;
console.log( raw );
});
Of course you can always just omit the field from being returned in the query result with the basic form provided by .select():
Model.findOne({ _id: id}, '-element', function(err,doc) {
console.log( doc );
});
Either form would remove that particular field from the response, but if you possibly want more control over the result than what can be provided by the field projection from .select() then use the .toObject() form and manipulate just as a plain JavaScript object.

Using 'generic' virtual for mongoose schema

I want to convert _id variable as id.
So i want to add virtual 'id' field to all the schema i am going to create, that will return the value of '_id' whenever i access 'id' field of the model.
from the documentation http://mongoosejs.com/docs/2.7.x/docs/virtuals.html
i found that, first i have to create schema then apply the virtual 'id' field individually.
I want to simply add virtual field to the base mongoose.Schema and then whenever i will create a new schema, that all will have virtual field without any manual effort on each of the individual schema.
EDIT :
i am also using Backbone.Model and i have created an 'id' field for each model. If i get the simply use id in the front end codes, i get the error that id field not exists. BUT when i set idAttribute as '_id' to each model then everything goes OK. That means backbone model want to have _id, and the reason behind mongoose schema have _id not id. So can i interpret that, mongoose does not automatically add virtual id mapped to _id? Correct me if i am wrong.
For backbone, "id" is it's default idAttribute name, so just don't add any code there and everything will work as intended.
For mongoose, the answer boils down to "it's complicated", but the main points are:
By default mongoose will give each schema a virtual called "id" which will be the document's _id as a string
However, by default .toJSON doesn't include virtuals, so when you send a mongoose document to backbone in the browser, it gets just "_id" and not "id"
to quickly get a JSON representation including the virtuals, use myModelInstance.toJSON({virtuals: true}). You'll get both "_id" and "id"
You need to read up on the transform options for toObject and toJSON to get a full picture of what you can do and how, but the gist is (based on examples straight from the docs)
// specify the transform schema option
if (!schema.options.toJSON) schema.options.toJSON = {};
schema.options.toJSON.transform = function (doc, ret, options) {
// remove the _id of every document before returning the result
delete ret._id;
}
schema.options.toJSON.virtuals = true;

Access mongoose non-schema values in Jade

I have a really weird problem in Jade where I cannot access the values that aren't defined in the Schema.
I'm using strict:false on my schema and saving values to it. My data looks like this:
{
"title" : "This is a title in the schema",
"notInSchema" : "This will never show up"
}
This works:
h1= post.title
This doesn't work:
h1= post.notInSchema
If I dump all my data into the template, I can see both pieces of data:
pre= JSON.stringify(options,null,'\t') //{"title" : "This is a title in the schema", "notInSchema" : "This will never show up"}
If I add notInSchema to my schema, it shows up. How can I do this without adding it?
Instead of passing the raw Mongoose document to Jade, pass its serialized version instead:
res.render('yourtemplate', {
post : post.toJSON() // .toJSON() is also called by JSON.stringify()
});
I believe Mongoose only creates accessors on a document for fields that are in the schema. Any other fields, even though they are stored in the database, don't get one so can't be accessed directly.
The documentation seems to suggest something similar:
NOTE: Any key/val set on the instance that does not exist in your
schema is always ignored, regardless of schema option.
EDIT: since you're dealing with result sets, you need to call toJSON on each document in it. The easiest way to do so is using map (hope I get the CF syntax right):
res.render "admin",
title : "Admin Dashboard"
results : results
users : results.users.map (user) ->
user.toJSON()
messages: req.flash() || {}
Although that would still leave results 'unprocessed'. Alternatively, you could leave the mapping to the separate steps in your async.series. For instance:
Company
.find()
.exec (err,companies)->
next(null,companies.map (company) ->
company.toJSON()
)
Or use toJSON in your template on any object that you need to access those "unschema'd" properties for.
I use:
model.find({Branch:branch},function (err, docs){
if (err) res.send(err)
res.render('index',
{tree: tree,
articulos: JSON.parse(JSON.stringify(docs))
})})
});

Resources