JSON object architecture looks different when I pass it to the client side - javascript

Here is my Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var messageSchema = new Schema({
requestNumber: String,
requestedDateTime: String,
reasons: String,
state: String,
hospital: String,
phone: String,
status: {type: String, default: 'Pending'},
latestUpdate: Date,
createdAt: {type: Date, default: Date.now}
});
module.exports = mongoose.model('Requests', messageSchema);
Below I am returning the collection with three components in it
ipcMain.on('load-requests', function(event) {
hosSchemaModel.find(function(err, hosSchema) {
if (err) {
console.log('inside error') // return res.send(err);
} else {
event.sender.send('requests-results', hosSchema) // this line of code passes hosSchema to the client side
console.log(hosSchema[0].state) //prints the state attribute of the first component in the collection without any errors.
}
});
});
When I try to console.log(hosSchema) in the server, I get the following printed to the terminal:
and I could successfully access the properties such as status of the first component in the collection by referring to its index hosSchema[0].status.
Below I am trying to print hosSchema to the console (in the front-end)
ipcRenderer.on('requests-results', (event, hosSchema) => {
console.log(hosSchema)
})
I get the result different from what they were looking in the terminal. below is the picture
and hosSchema[0].status returns undefined.
My questions are:
1) why hosSchema[0].status doesn't work in the front-end?
2) what is the correct way to access the properties in the client-side?

All you have to do in the front end is to use hosSchema[0]._doc.status instead of hosSchema[0].status

Related

How can I make a private message schema for mongoose?

I am trying to make a messages schema + routes for my backend. I want that two users can write a message to each other and the message has to be stored for both of them.
I made the the user-model-schema and the user-routes, they are working but I'm stuck with the messaging.
mongoDB should contain the message
how can I manage sending messages?
Here is what I tried so far
messages-route:
var express = require("express");
var User = require("../models/users.js");
var router = express.Router();
const message = require("../models/messages");
router.post("/:recipient", (request, response) => {
User.find({
username: [request.body.sender, request.params.recipient],
// }, {
// message: request.body.message
// }, {
// upsert: false,
// new: true,
})
.then((users) => {
users.forEach((user) => {
user.updateMany({
message: request.body.message
})
})
response.status(200).json(users);
})
.catch((error) => {
response.status(500).json(error);
});
});
module.exports = router;
and my messages-schema:
var mongoose = require("mongoose");
var UserMessage = new mongoose.Schema({
user: { "type": mongoose.Schema.ObjectId, "ref": "User" },
username: String,
view: {
inbox: Boolean,
outbox: Boolean,
archive: Boolean
},
content: {type: String},
read: {
marked: { "type": Boolean, default: false },
date: Date
}
});
var schemaMessage = new mongoose.Schema.ObjectId({
from: String,
to: [UserMessage],
message: String,
created: Date
});
module.exports = mongoose.model("Messages", UserMessage);
I'm very unsure with the schema, I put in some suggestions I found here on stackoverflow.
Thanks!
I'm now making a messages Schema, and i thought of something like this:
const ChatSchema = new mongoose.Schema({
participants: [{type: mongoose.Schema.objectId, ref: "users"}],
last_message: Number,
_id: {type: mongoose.Schema.objectId}
//...
})
Here you could use the same schema to make chat groups, and it will work having a separate document for each message with a field with the chatroom _id, so you could query them
And you might be thinking, why not put all the messages in an array on ChatSchema?
Well, because we don't want the users to recieve all their messages each time they enter a chat.
I know, you might be thinking about something like this to prevent that over-load of data to the client
MessageSchema.find(({ ... })
.sort({ updatedAt: -1 })
.limit(20)
But here you're still recieving all the messages from the database to the server, and users could have even 1000 messages per chat, so an idea that came to my mind was making MessageSchema like this:
const MessageSchema = new mongoose.Schema({
message: String,
chatRoom_id: {type: mongoose.Schema.objectId},
sentBy: {type: mongoose.Schema.objectId, ref: "users"},
seenBy: [{ user: {type: mongoose.Schema.objectId, ref: "users"}, seen: Boolean }],
numberOfMessage: Number
//...
})
And the magic is with numberOfMessage, because you could query the MessageSchema with comparison operators like this:
const currentMessage = 151 //this is the numberOfMessage number of the last message the user saw, and when the user scrolls up the chat you could send the numberOfMessage of the last loaded message.
//To know from wich numberOfMessage start, just use the ``last_message`` field from the chatroom's ``ChatSchema``
const quantityNewMessages = 10 //this is the quantity of new messages you want the user to recieve
MessageSchema.find({
chatRoom_id,
numberOfMessage:
{ $lt: currentMessage , $gte: currentMessage + quantityNewMessages } //we use less than operator because the user will always recieve the last message first, so the previous messages are going to have a numberOfMessage less than this first message
})
And it will return us an array of 10 messages, wich you can concat to the messages array you already have in your frontend.
take note:
With this MessageSchema, all the users will share the same document for each message, you could make a separate document of a message for each user in a chatroom, so each user can delete a message without affecting the others.
I don't recommend you saving a username field, because the user could change it's username and if he does that, you would have to update ALL message documents with that username to the new username, so just leave the ref and populate it
You shouldn't put the document object in the to field, make it a separate document and only save it's ref. But I don't recommend doing it that way either
Don't use users.forEach because it modifies the array, use users.map because it returns a new array and doesn't mutates the original array
I see you have a bug, you are asking the data with the returned variable of the forEach( user => user.update(...) ), it should be map( user => UserSchema.update({ _id: user._id }) )
But still, looping an array and making a call to the DB each time is very expensive and will lag the server, so use something like the ChatSchema I showed you, because you could get the chatroom information, and with the _id of that chatroom, query the newest messages
I've not tested this code, i'm about to do it. If you run into any problem feel free to comment

Schema hasn't been registered for model in Schema but not others from the same source

I am trying to populate a node express route with information from Schemas, and I keep getting this error. What I cannot understand is that I am referencing three different fields in the same exact Schema and for some reason, I am only getting this error for one of those fields.
This is my route function where I am getting "MissingSchemaError: Schema hasn't been registered for model "completed_by_user""
// Schemas
const Transaction = require ("../models/transaction");
User = require ("../models/user");
Ticket = require ("../models/ticket");
Job = require ("../models/job");
Client = require ("../models/client");
// Functions
let numberWithCommas = require("../functions/numberWithCommas");
module.exports = function(app) {
// =======================Tickets
// index
app.get("/tickets", function(req, res){
Ticket.find({}).populate("created_by", "assigned_user", "completed_by_user").exec(function(err, tickets){ //This is where it happens
if(err){
console.log(err)
} else {
res.render("tickets", {tickets: tickets});
}
});
});
And this is the Ticket Schema itself:
const Transaction = require ("./transaction");
User = require ("./user");
Ticket = require ("./ticket");
Job = require ("./job");
Client = require ("./client");
// =======================Ticket Schema
var ticketSchema = new mongoose.Schema({
ticket_name: String,
description: String,
created_by: [{type: mongoose.Schema.Types.ObjectID, ref: "User"}],
assigned_user: [{type: mongoose.Schema.Types.ObjectID, ref: "User"}],
completed_by_user: [{type: mongoose.Schema.Types.ObjectID, ref: "User"}],
due_date: {type: Date},
completed_date: {type: Date},
completed_description: String,
date_added: {type: Date, default: Date.now}
});
module.exports = mongoose.model("Ticket", ticketSchema);
I am not getting this error for "created_by" or for "assigned_user" but I am getting it for "completed_by_user." I don't understand why this would be since they are all populated in the same Schema. This is not the only occurrence of this type of issue I am having, but I am sure it is for the same reason. I even tried changing the order I require the schemas and that has not helped either. Is there something obvious I am missing? Thanks.
.populate(["created_by", "assigned_user", "completed_by_user"])
Try this because .populate function takes only one argument by putting it into array it takes multiple

Update Array attribute using Mongoose

I am working on a MEAN stack application in which i defined a model using following schema:
var mappingSchema = new mongoose.Schema({
MainName: String,
Addr: String,
Mapping1: [Schema1],
Mappings2: [Schema2]
},
{collection : 'Mappings'}
);
I am displaying all this data on UI and Mapping1 & Mapping2 are displayed in the 2 tables where I can edit the values. What I am trying to do is once I update the values in table I should update them in database. I wrote put() api where I am getting these two updated mappings in the form of object but not able to update it in database. I tried using findAndModify() & findOneAndUpdate() but failed.
Here are the Schema1 & Schema2:
const Schema1 = new mongoose.Schema({
Name: String,
Variable: String
});
const Schema2 = new mongoose.Schema({
SName: String,
Provider: String
});
and my put api:
.put(function(req, res){
var query = {MainName: req.params.mainname};
var mapp = {Mapping1: req.params.mapping1, Mapping2: req.params.mapping2};
Mappings.findOneAndUpdate(
query,
{$set:mapp},
{},
function(err, object) {
if (err){
console.warn(err.message); // returns error if no matching object found
}else{
console.log(object);
}
});
});
Please suggest the best to way update those two arrays.
UPDATE :
I tried this
var mapp = {'Mapping2': req.params.mapping2};
Mappings.update( query ,
mapp ,
{ },
function (err, object) {
if (err || !object) {
console.log(err);
res.json({
status: 400,
message: "Unable to update" + err
});
} else {
return res.json(object);
}
});
what I got is
My array with size 3 is saved as String in Mapping2 array.
Please help. Stuck badly. :(
From Mongoose's documentation I believe there's no need to use $set. Just pass an object with the properties to update :
Mappings.findOneAndUpdate(
query,
mapp, // Object containing the keys to update
function(err, object) {...}
);

Why are my Mongoose One-To-Many Relationships not associating properly?

Does anyone know why the following one-to-many relationship between "users" and "posts" (users can have many posts) is not working? It appears I have setup my mongoose associations correctly, but when a new post is created, not only is it not assigned a user, but the users themselves are also not associated with any posts. I'm not sure what I might be doing wrong here.
If you see the JSON object below, it should have a user value, denoting the user whom created the post. You'll see in the Post Model below, that a user value should be created, but does not.
What am I doing wrong?
Here's the JSON object after creating a new post
{
__v: 0
_id: "587ee8f5a99b1709b012ce8f"
createdAt: "2017-01-18T04:03:01.446Z"
message: "This is my first test post!"
updatedAt: "2017-01-18T04:03:01.446Z"
}
Question: Why is the user field missing from the JSON above despite being created in the Post Model below?
Here's my Post Model:
// Setup dependencies:
var mongoose = require('mongoose');
// Setup a schema:
var PostSchema = new mongoose.Schema (
{
message: {
type: String,
minlength: 2,
maxlength: 2000,
required: true,
trim: true,
}, // end message field
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
},
{
timestamps: true,
}
);
// Instantiate our model and export it:
module.exports = mongoose.model('Post', PostSchema)
Here's my User Model:
// Setup dependencies:
var mongoose = require('mongoose');
// Setup a schema:
var UserSchema = new mongoose.Schema (
{
username: {
type: String,
minlength: 2,
maxlength: 20,
required: true,
trim: true,
unique: true, // username must be unique
dropDups: true,
lowercase: true,
validate: {
validator: function(username) {
var regex = /^[a-z0-9_]+$/i;
return regex.test(username);
},
message: 'Username may contain only letters, numbers or underscores.',
},
}, // end username field
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}],
},
{
timestamps: true,
});
// Instantiate our model and export it:
module.exports = mongoose.model('User', UserSchema)
Here's the Controller that queries the DB:
Note: This is the method that runs when the post form is submitted.
// Grab our Mongoose Models:
var User = require('mongoose').model('User');
var Post = require('mongoose').model('Post');
module.exports = {
// Creates a new post for logged in user:
newPost: function(req, res) {
Post.create(req.body)
.then(function(newPost) {
return res.json(newPost);
})
.catch(function(err) {
return res.json(err);
})
}
};
Does anyone know if my associations are improperly setup and this is why I'm not getting any actual posts or users to show up in their respective fields?
It seems that my server-side controller is firing properly, as the post is actually created. But the associations themselves are not linking up and I'm not sure what I'm doing wrong.
I'm adding just a simple answer below to follow up with the example above. Essentially, #cdbajorin was correct, I was absently thinking there was some automation going on and was not appropriately following through the proper mongoose commands to achieve my desired results.
The solution to my question is as follows:
In the User Model, update the UserSchema posts attribute to be an empty array, instead of a mongoose.Schema.Types.ObjectID, since an object ID is not stored here anyhow and I misunderstood how this works.
The code:
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
}],
Instead, should be written simply:
posts: [],
The newPost method, in the server Controller, should be modified as follows (see comments inline for clarification):
newPost: function(req, res) {
// creates new post:
Post.create(req.body)
.then(function(newPost) {
// look up current user based on session ID:
// note: session setup not shown in this example.
User.findById(req.session.userID)
.then(function(user) {
// push new post into users.posts array from model setup**:
user.posts.push(newPost);
user.save();
return res.json(newPost);
})
})
.catch(function(err) {
return res.json(err);
})
This does solve the issue of the new post being generated, and then pushed into a user's posts array (from the UsersSchema).
Though the issue from the initial post is solved, one may question if this is the best use of database management. Storing posts inside of a user, as this example does, can take up a lot of space as users and posts start to add up.
This post ends up being duplicated in the database twice: first, as a document itself in the posts collection, and secondly, as an object in the posts array within the UserSchema.
A better solution is to keep the post as a unique document in the posts collection, but add the userID from the session information to it. Then, if all of user's posts are needed for any reason, a query to the Posts collection, based on the userID, would return all posts with that userID assigned to it. Then, only one copy of the post exists in the DB instead of two.
** Additional Note: Another way to modify the existing document would be to use an instance method, where an actual method would be inserted into the User Model (Schema) file, and called when needed:
For example, inserting the following code before the module.exports line in the UserSchema Model above, allows for convenient access this function when needed:
UserSchema.methods.addPost = function(post) {
this.posts.push(post);
this.save();
return true;
};
To call this instance method from our server Controller, we could re-write our Controller as follows:
User.findById(req.session.userID)
.then(function(user) {
// call our instance method above:
user.addPost(newPost);
return res.json(newPost);
});
The post will be pushed and saved by the instance method, which has been built into the instance object itself.

Update/Put error save in Express and Mongoose

I am beginner in Express. I have the following code in my router/controller for update a model. In one hand I don't want to modify the date of "create_date" parameter, and on the second hand this code returns me a error.
updateFood = function(req, res){
Food.findById(req.params.id, function(err, food){
food.food_name = req.body.food_name;
food.description = req.body.description;
food.image = req.body.image;
food.create_date = Date.now();
food.category = req.body.category;
Food.save(function(err){
if (!err){
console.log("updated!");
} else {
console.log(err);
}
});
res.send(food);
});
};
Here is my schema:
var food = new Schema({
food_name: {type: String, unique: true},
description: String,
image: String,
create_date: {type: Date, default: Date.now()},
category: {
type: String,
cats: ['Meat', 'Fish', 'Vegetables']
}
});
module.exports = mongoose.model('Food', food);
When I try to update a food with Postman with PUT. The console returns me the following response:
Food.save(function(err){
^
TypeError: Object function model(doc, fields, skipId) {
if (!(this instanceof model))
return new model(doc, fields, skipId);
Model.call(this, doc, fields, skipId);
} has no method 'save'
What can I do? Anyone knows where is my mistake? Thanks.
I believe you meant food.save(..); instead of Food.save(..);, but if all you're doing is updating the model, you could use findByIdAndUpdate() instead.

Categories

Resources