Backbone Model Save: sending fields as "model" subobject - javascript

User Model
define(
[
'backbone'
],
function (Backbone) {
return Backbone.Model.extend({
url: '/proxy.php/users.json',
defaults: {
'first_name': '',
'last_name': '',
'work_email': ''
},
validation: {
first_name: {
required: true,
msg: 'Please enter a first name'
},
last_name: {
required: true,
msg: 'Please enter a last name'
},
work_email: {
required: true,
msg: 'Please enter a valid email'
}
}
});
}
);
View save data
onSave: function (ev) {
ev.preventDefault()
var details = $('.edit-user-form').serializeObject()
var object = new User()
return object.save(details, {
success: function (response) {
console.log(response, 'response')
}
})
},
details =
{first_name: "", last_name: "", birthdate: "", job_title: "", job_start_date: ""…}
birthdate: ""
first_name: ""
job_probation_ends: ""
job_start_date: ""
job_title: ""
last_name: ""
personal_address: ""
personal_email: ""
personal_phone_number: ""
work_address: ""
work_email: ""
work_phone_number: ""
The problem, the request sent by Backbone sends Form Data as:
model:{"first_name":"","last_name":"","work_email":"","birthdate":"","job_title":"","job_start_date":"","job_probation_ends":"","work_address":"","work_phone_number":"","personal_email":"","personal_address":"","personal_phone_number":""}
Why is it making the attributes a sub object of model? I would like the attributes sent as the root.

If you want to modify the structure of the data you send to the server, then override the toJSON method for your model:
toJSON: function () {
return { // structure the model as you wish here };
}

Related

postman returning null with 200 status code

getting null value as response with 200 status code. i want to see the profile details as response but instead of that showing null value with no error status code in my postman i dont find any error on my code. why it shows like this ? i want to see profile details as response after sending
Router.post
router.post(
'/',
[
auth,
[
check('status', 'Status is required').not().isEmpty(),
check('skills', 'Skills cannot be empty').not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubusername,
skills,
youtube,
twitter,
instagram,
linkedin,
} = req.body;
const profileFields = {};
profileFields.user = req.user.id;
if (company) profileFields.company = company;
if (website) profileFields.website = website;
if (location) profileFields.location = location;
if (bio) profileFields.bio = bio;
if (status) profileFields.status = status;
if (githubusername) profileFields.githubusername = githubusername;
if (skills) {
profileFields.skills = skills.split(',').map(skill => skill.trim());
}
// creating object for socila links
profileFields.social = {};
if (youtube) profileFields.social.youtube = youtube;
if (twitter) profileFields.social.twitter = twitter;
if (instagram) profileFields.social.instagram = instagram;
if (linkedin) profileFields.social.linkedin = linkedin;
try {
let profile = await Profile.findOne({ user: req.user.id });
if (profile)
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
);
return res.json(profile);
// create
profile = new Profile(profileFields);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err);
res.status(500).send('server error');
}
}
);
here is profile schema looks like
const ProfileSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
company: {
type: String,
},
website: {
type: String,
},
status: {
type: String,
required: true,
},
location: {
type: String,
},
skills: {
type: [String],
required: true,
},
bio: {
type: String,
},
githubusername: {
type: String,
},
experience: [
{
title: {
type: String,
required: true,
},
company: {
type: String,
required: true,
},
location: {
type: String,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
education: [
{
school: {
type: String,
required: true,
},
degree: {
type: String,
required: true,
},
fieldofstudy: {
type: String,
required: true,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
social: {
youtube: {
type: String,
},
twitter: {
type: String,
},
linkedin: {
type: String,
},
instagram: {
type: String,
},
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = Profile = mongoose.model('profile',ProfileSchema)
your code logic has problem.
let profile = await Profile.findOne({ user: req.user.id }); if (profile) //update profile = await Profile.findOneAndUpdate( { user: req.user.id }, { $set: profileFields }, { new: true } ); return res.json(profile);
here, if you can't find the record in database, you still return and there is no value so that you got null response. i suggest you remoe the return res.json(profile); into if statement
Back to the basics, the if statement.
if (profile){
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
);
return res.json(profile);
}
You need to use brackets {}.
In your code, return res.json(profile); gets fired no matter if the response is null or not
the problem is with your syntax you need to add curly braces
if (profile){
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
)};

Mongoose populate returns an empty array | multiple levels of embedded documents

I am trying to populate my ChatRoom model with the User reference. However, it returns a ChatRoom object with only _ids where I expected usernames, as if I never applied populate on it.
Here is an extract of my ChatRoom model :
const ChatRoom = mongoose.model("ChatRoom", {
sender: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
roomname: { type: String, default: "new room" },
messages: [
{
messages: {
type: mongoose.Schema.Types.ObjectId,
ref: "Message",
},
meta: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
delivered: Boolean,
read: Boolean,
},
],
},
],
participants: [
{
user: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
},
],
isPrivate: { type: Boolean, default: "false" },
});
My User model :
const User = mongoose.model("User", {
username: { required: true, unique: true, type: String },
avatar: Object,
token: String,
hash: String,
salt: String,
chatroom: {
type: mongoose.Schema.Types.ObjectId,
ref: "ChatRoom",
},
});
As this seems to be a recurrent issue, I tested several StackOverflow answers for my populate code :
Using populate('participants.user') and 'model: user' or just populate('participants.user'), same solution here:
const chatroom = await ChatRoom.findById(req.params.id)
.populate([
{
path: "participants.user",
model: "User",
},
])
.exec((err, user) => {
if (err) {
console.log("error", err);
} else {
console.log("Populated User " + user);
}
});
The console.log returns :
Populated User { _id: new ObjectId("62262b342e28298eb438d9eb"),
sender: new ObjectId("6225d86c9340237fe2a3f067"), roomname:
'Hosmeade', participants: [ { _id: new
ObjectId("6225d86c9340237fe2a3f067") } ], isPrivate: false,
messages: [], __v: 0 }
As if no populate method was ever applied. On the client side, I get an empty string.
Checking my documents aren't empty, this link mentions that Mongoose get problems with detecting referring model across multiple files but the solution doesn't work for me :
_id:6225d86c9340237fe2a3f067 username:"Berlioz" token:"rTCLAiU7jq3Smi3B"
hash:"wvJdqq25jYSaJjfiHAV4YRn/Yub+s1KHXzGrkDpaPus="
salt:"hZdiqIQQXGM1ryYK" avatar:Object
__v:0
If I remove the .exec(...) part, I get the info on the client side, but participants is still filled with only id :
chatroom response : Object { _id: "62262bb14e66d86fb8a041e8",
sender: "6225d86c9340237fe2a3f067", roomname: "Very secret room",
participants: (1) […], isPrivate: false, messages: [], __v: 0 }
I also tried with select: 'username' and get the same result as above :
const chatroom = await ChatRoom.findById(req.params.id).populate({
path: "participants.user",
select: "username",
});
Populating it "as an array"
Changing type of participants.user in my ChatRoom model into an Object (nothing changes)
If needed hereafter are my repos:
Client side and Backend
I run out of ideas on how to debbug my code. Any help would be great !

forEach nested to match

Here i made a code.
let StaffParsed = JSON.parse(params.StaffJson);
console.log(StaffParsed)
Here is the result below fo console log.
Object
cellPhoneNo: "1234567890"
createdBy: "1"
createdDate: "2020-05-09T17:26:31.743"
email: "ravi#email.com"
fax: "1234567890"
firstName: "Ravi"
id: 1004
lastName: "Nikam"
phoneNo: "1234567890"
profilePic: ""
sendEmail: false
sendPhone: false
status: "3"
title: "Mr."
type: "2"
updatedBy: "1"
updatedDate: null
username: "ravi109"
__proto__: Object
I have this model created here is the code below.
public StaffModel : Staff = new Staff();
console.log(this.StaffModel);
Its console log result is below.
Staff
CellPhoneNo: 0
CnfPassword: ""
CreatedBy: ""
CreatedDate: null
Email: ""
Fax: 0
FirstName: ""
FormStaffGroup: FormGroup {validator: null, asyncValidator: null, pristine: true, touched: false, _onCollectionChange: ƒ, …}
Id: null
LastName: ""
Password: ""
PhoneNo: 0
ProfilePic: ""
SendEmail: false
SendPhone: false
Status: "0"
Title: ""
Type: "0"
UpdatedBy: ""
UpdatedDate: null
UserName: ""
__proto__: Object
enter code here
Now i want to match with the above first object list with the second list and update the second list model, so far i have tried this code.
Object.keys(StaffParsed).forEach(function(keyParsed) {
Object.keys(this.StaffModel).forEach((keyModel: string) => {
if(keyParsed == keyModel){
keyParsed = this.StaffModel[keyModel];
}
});
});
But in return, it shows error like this .
Your problem is this part:
... .forEach(function(keyParsed) {
Object.keys(this.StaffModel)
this does not propagate into functions like that. As such, the this inside the function has a different value from the this in the outside function.
If you want the function to inherit the this of the outside scope, use an arrow function instead. ((keyParsed) => { instead of function(keyParsed) {)
In your code this in this.StaffModel[keyModel] may refer to the function not global.
Try this:
let that = this;
Object.keys(StaffParsed).forEach(function (keyParsed) {
Object.keys(that.StaffModel).forEach((keyModel: string) => {
if (keyParsed == keyModel) {
keyParsed = that.StaffModel[keyModel];
}
});
});

Mongoose node return multiple arrays of referenced objects from document

I am working on a node backend API with mongoose. I have 2 schemas one User schema and one Follow schema(saved as users and follows in mongo). The follow schema fields followers and following hold an array of ObjectIds that refer to User objects. I am trying to return the Referenced objects in in the arrays so that I can respond with an object to the client that contains an array of userFollowing and userFollowers containing user objects, a but I am unable to populate the output.
I will also need to be able to filter the returned objects to only return 'username bio image email first_name surname join_date'.
My current incorrect output is below. I am not sure if its an error in my query or if I am using the correct approach.
[ { _id: 5c7dc1b92f3f1dd8ad9df993,
user: 5c7d93b57a29ce05a096c492,
userFollowing: [],
userFollowers: [] } ]
var mongoose = require('mongoose');
let Schema = mongoose.Schema;
var FollowSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
followers: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
following: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
}, { toJSON: { virtuals: true } }
);
module.exports = mongoose.model('Follow', FollowSchema);
// username must be unique and is required
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true,
required: true
},
email: {
type: String,
unique: true,
},
first_name: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
join_date: {
type: Date,
default: Date.now
},
bio: {
type: String,
default: 'Tell me about yourself'
},
image:{
type: String,
default: 'profile.jpg'
},
password: {
type: String,
required: true
}
});
User.findOne({
'username': username
}, function (err, user) {
if (!user) {
return res.json({
'state': false,
'msg': `No user found with username ${username}`
})
} else {
const user_id = user._id;
Follow.aggregate([{
$match: {
"user": mongoose.Types.ObjectId(user_id)
}
},
{
$lookup: {
"from": "follows",
"localField": "following",
"foreignField": "_id",
"as": "userFollowing"
}
},
{
$lookup: {
"from": "follows",
"localField": "followers",
"foreignField": "_id",
"as": "userFollowers"
}
}, {
$project: {
"user": 1,
"userFollowers": 1,
"userFollowing": 1
}
}
]).exec(function (err, doc) {
console.log(doc);
res.json({
'state': true,
'msg': 'Follow list',
'doc': doc
})
})
}
})

Why doesn't mongoose ref work for me when I'm trying to reference objects of another schema?

I'm trying to access the attributes of an address of a store, but I keep on getting 'undefined'. Turns out that address is only an id, even though I declared a 'ref' in the address's schema. What am I doing wrong here?
Output from initStores
{ name: 'Wegmans',
address: 53b998d9fcf740e07a4d03f7,
_id: 53b998d9fcf740e07a4d03f8,
items: [] }
53b998d9fcf740e07a4d03f7
undefined
routers/index.js
router.post('/initStores', function(req, res) {
var address = new Address({
street: '650 Hylan Dr',
city: 'Rochester',
state: 'NY',
zipcode: '14623',
telephone: '123-456-7890'
});
// address.save();
var store = new Store({
name: 'Wegmans',
address: address
});
console.log( store );
console.log( store.address );
console.log( store.address.street );
// store.save();
}
models/address.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var AddressSchema = new Schema({
type: { type: String, default: 'Store' }, // Store, apartment, house, headquarter
street: { type: String, require: true },
city: { type: String, require: true },
state: { type: String, require: true },
zipcode: { type: String, require: true },
country: { type: String, default: 'United States' },
telephone: { type: String, default: '555-555-5555' }
});
mongoose.model('Address', AddressSchema);
models/store.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var StoreSchema = new Schema({
name: { type: String, require: true },
address: { type: ObjectId, ref: 'Address' },
items: [ { type: ObjectId, ref: 'Item' } ]
});
mongoose.model( 'Store', StoreSchema );
For a referenced schema this code works absolutely as designed. Fields in the "Address" schema are not part of the the "Store" schema at all. What the referenced design does here is just stores the _id value of the related document, where the rest of that document will reside in it's own collection.
So, in fact you are actually creating these separately and only ever after a .populate() operation do the different documents actually "appear" to be "joined", just as they would appear in a native way if the document was in fact "embedded".
Store.findById(store._id).populate("address").exec(err,newstore) {
console.log(newstore);
});
Or since you really have the "store" object already and making sure "saves" have completed:
async.series(
[
function(callback) {
address.save(function(err,address) {
callback();
});
},
function(callback) {
store.save(function(err,store) {
Store.populate(store,{ path: "address"},function(err,store) {
console.log(store);
callback();
});
});
}
]
);
The only ways in which this can and "should" appear as a whole object without the .populate() which needs the data to be saved, is either by embedding the address so it is part of the "Store", and not saved to a different model and collection:
var StoreSchema = new Schema({
name: { type: String, require: true },
address: {
"type": { type: String, default: 'Store' }, // Store, apartment, house, headquarter
street: { type: String, require: true },
city: { type: String, require: true },
state: { type: String, require: true },
zipcode: { type: String, require: true },
country: { type: String, default: 'United States' },
telephone: { type: String, default: '555-555-5555' }
},
items: [ { type: ObjectId, ref: 'Item' } ]
});
Or if your purposes are just purely logging on creation then you can convert and manipulate with .toObject():
var raw = store.toObject();
raw.address = address.toObject();
console.log( raw );
But otherwise with a referenced model, the intention is that the data is not part of the same object until a .populate() is called.

Categories

Resources