Update element from user profile in Meteor - javascript

I am trying to update firstName field created in user.profile using onCreateUser:
Accounts.onCreateUser(function(options, user) {
user.profile = options.profile || {};
user.profile.firstName = options.firstName;
return user;
});
Also I use allow:
Meteor.users.allow({
update: function(userId, doc, fields, modifier) {
if (fields === "profile.firstName") {
return true;
}
}
});
When I use:
Meteor.users.update({
_id: Meteor.userId()
}, {
$set: {
profile: "George"
}
});
It works but it is not what I need.
What I need is to update firstName:
Meteor.users.update({
_id: Meteor.userId()
}, {
$set: {
profile.firstName: "George"
}
});
But I get this error:
SyntaxError: missing : after property id
What am I missing?

If you are using the dot notation you need to enclose the whole dotted field name in quotes.
In your case:
Meteor.users.update({
_id: Meteor.userId()
}, {
$set: {
"profile.firstName": "George"
}
});
Read more about updating an embedded field.

Related

How to access array elements that are defined in another array of Mongoose scheme object Array?

This is the User schema in mongoose:
var userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
},
name: {
type: String,
required: true,
},
Addtasks: [
{
topic: String,
words: Number,
keywords: String,
website: String,
otherdetails: String,
exampleRadios: String,
deadline: Date,
Date: String,
fileName: String,
Bigpaths: [],
},
],
});
module.exports = mongoose.model('User', userSchema);
I want to use/access the Bigpaths array, which is defined inside the Addtasks array, which is defined in User. Data is already are there in mongoDB, which I have inserted via UI page. I am trying the following code but I am getting this error in console:
data.Addtasks[Object.keys(data.Addtasks).length - 2].Bigpaths.forEach(
(element) => {
// ...
}
)
as
TypeError: Cannot read property 'Bigpaths' of undefined
at \Desktop\grumpytext\routes\index.js:99:71
Code:
const { files } = req;
User.findOne({ email: req.user.email }, function (error, data) {
if (error) {
console.log('Three');
} else if (data) {
if (Object.keys(data.Addtasks).length > 1) {
data.Addtasks[Object.keys(data.Addtasks).length - 2].Bigpaths.forEach(
(element) => {
files.forEach((currentElement) => {
if (element.name == currentElement.filename) {
files.pull(currentElement.filename);
}
});
}
);
}
}
});
How to resolve this error or how to access all the elements of Bigpaths array so that I can iterate it with forEach loop?
I'm not sure here, but I think you need to populate Addtasks prior to manipulating it:
const files = req.files;
User.findOne({email:req.user.email}).populate('Addtasks').exec((error, data) => {
if (error) {
console.log("Three");
}
else
{
if(data)
{
if(Object.keys(data.Addtasks).length > 1)
{
console.log("Addtasks count: " + Object.keys(data.Addtasks).length);
data.Addtasks[Object.keys(data.Addtasks).length - 2].Bigpaths.forEach(element => {
files.forEach(currentElement => {
if(element.name == currentElement.filename)
{
files.pull(currentElement.filename);
}
})
});
}
}
}
});
Please notice the log console.log("Addtasks count: " + Object.keys(data.Addtasks).length); - in case the solution does not work, I advise to add some prints, especially to check if the count of elements is as expected or properties within an object are fine.

Remove Object from Array MongoDB

I need to remove a specific object from my mongoDB array.
Should remove the info above inside the red cube but (0: Object)
I tried the way I show below but didn't work.
And I need to remove the entire object but can't pass the values directly in the query so I need to grab the info from mongoDB and remove them.
router.post("/deleteArquive/:id", ensureAuthenticated, (req, res) => {
var id = mongoose.Types.ObjectId(req.params.id);
House.update(
{ "expensesHouse._id": id },
{
$pull: {
expensesHouse: {
status: "expensesHouse.status",
_id: "expensesHouse._id",
expenseType: "expensesHouse.expenseType"
}
}
}
).then(house => {
if (house.userID !== req.user.id) {
res.redirect("/houses/houses");
} else {
req.flash("success_msg", "House removed!");
res.redirect("/houses/houses");
}
});
});
If I understand the requirements correctly, this should do the job:
House.update(
{ "expensesHouse._id": id },
{
$pull: {
expensesHouse: {
_id: id
}
}
}
)

Return the inserted sub-document

Im building an app where i need to add messages as sub documents in a chat room. i need to return the data of the the sub document as soon as i insert it to the existing room. this is my code
Room.findOne({ roomname: data.room }, (err, room) => {
room.messages.push({ username: data.username, message: data.message });
room.save((err, room) => {
socket.broadcast.to(data.room).emit("new message", {
username: room.messages.slice(-1).name,
message: room.messages.slice(-1).message,
createdat: room.messages.slice(-1).createdat
});
});
});
So this the code i have used to retrieve last sub document. Is there any other way to achieve this?
Use .findOneAndUpdate() with $push instead. That way you only touch the database "once", and it also avoids the problem that something else possibly modifies the document and you end up overwriting that. This avoids the danger of the .find() then .save() pattern:
Room.findOneAndUpdate(
{ roomname: data.room },
{ "$push": {
"messages": { username: data.username, message: data.message }
}},
{ "new": true },
(err, room) => {
let message = room.messages.slice(-1)[0];
socket.broadcast.to(data.room).emit(
"new message",
Object.keys(message).filter(k => k !== "_id")
.reduce((acc,curr) => Object.assign(acc,{ [curr]: message[curr] }),{})
);
}
);
Also, just .slice(-1)[0] to get the whole object and just return it, or filter out the unwanted keys just as shown above.
Or even simply just return all the fields from the array element and $slice the array to return from the query from the server:
Room.findOneAndUpdate(
{ roomname: data.room },
{ "$push": {
"messages": { username: data.username, message: data.message }
}},
{ "new": true, "fields": { "messages": { "$slice": -1 } } },
(err, room) => {
socket.broadcast.to(data.room).emit(
"new message", room.messages[0]
);
}
);
room.messages.slice(-1).name
This is incorrect, demo below
[1,2,3].slice(-1)
// returns [3], not 3
You still have to use index
room.messages.slice(-1)[0].name
// or simply
room.messages[room.messages.length - 1].name

Exception from Tracker recompute function and sub user id, Match error

I have a user publish and subscribe problem. When I click on a user name, it is supposed to show: [1] user's profile image; and [2] all posts from that user.
However it just shows a loading spinner screen and the below errors. If I try a couple of refresh or re-clicking the name, the page eventually loads with some lag.
I suspect a client race condition but I tried adding a (!this._id) return [ ] or this.ready();, the posts would flash on screen once and not show up thereafter. I cant remove the check as it throws a no check error.
If theres anywhere to simplify showing posts of the user, please kindly advise. Thanks!
error on the browser console:
Exception from Tracker recompute function: meteor.js:930:11
undefined meteor.js:932:11
selected portions of the key error shown on terminal:
> I20170409-11:51:58.787(8)? Exception from sub user id
> BRFKAiwEXKootpbwY Error: Match error: Expected string, got null
> (packages/check/match.js:34:1) I20170409-11:51:58.788(8)? at
> Subscription.<anonymous> (server/server.js:86:2)
> I20170409-11:51:58.788(8)? at Subscription.prepareOptions
> (packages/reywood_publish-composite/packages/reywood_publish-composite.js:440:1)
> I20170409-11:51:58.788(8)? at Subscription._handler
> (packages/reywood_publish-composite/packages/reywood_publish-composite.js:408:1)
> I20170409-11:51:58.788(8)? at packages/check/match.js:107:1
> at Object.exports.Match._failIfArgumentsAreNotAllChecked
> (packages/check/match.js:106:1) I20170409-11:51:58.788(8)? at
> maybeAuditArgumentChecks
> Match failed [400]
The server publish
Meteor.publish('userDetails', function() {
var fields = {
username : 1,
emails : 1,
profile : 1,
md5hash : 1
};
return Meteor.users.find( {}, { fields: fields });
});
Meteor.publishComposite('user', function (_id) {
check(_id, String); // cant remove this check, throws error
//if (!this._id) return this.ready(); or [] doesnt work
return {
find: function() {
return Meteor.users.find({ _id: _id }, {
fields: {
username : 1,
emails : 1,
profile : 1,
md5hash : 1
}
});
},
children: [
{
find: function(user) {
return Posts.find({ userId: user._id });
}
}
]
};
});
Router code
Router.route('/users/:_id', {
name: 'users.show',
onBeforeAction: function () {
if( this.params._id === Meteor.userId() ){
Router.go('profile');
} else {
this.next();
}
}
});
the page js
Template.usersShow.onCreated(function(){
var self = this;
self.autorun(function(){
self.subscribe('user', Router.current().params._id);
});
});
Template.usersShow.helpers({
user: function () {
return Meteor.users.findOne({ _id: Router.current().params._id });
},
posts: function () {
return Posts.find({ userId: Router.current().params._id });
}
});
I read the Pub/Sub section in the official document, but never seen the description about the property _id in the context this.
I think change this._id to _id will work correctly.
Meteor.publishComposite('user', function (_id) {
// Change `this._id` to `_id`
if (!_id) return this.ready(); // or [];
return {
find: function() {
return Meteor.users.find({
_id: _id
}, {
fields: {
username: 1,
emails: 1,
profile: 1,
md5hash: 1
}
});
},
children: [
{
find: function(user) {
return Posts.find({userId: user._id});
}
}
]
};
})

Sails.js query db by foreign key

I'm wondering how to make a query by foreign key using the default Waterline model.
I have two models Post and Category - Post has a foreign key category. I need to make a query like so:
Post.find({
where: {
category: query
}
}).exec(function (err, data) {});
In this case query is a string so the results returned should be Posts containing searched category.
What is the best way to do this?
Note: Current example does not work
Your model should be
// Post
module.exports = {
attributes: {
name: {
type: 'string'
},
category: {
model: 'category'
}
}
};
// Category
module.exports = {
attributes: {
name: {
type: 'string'
},
post: {
collection: 'Post',
via: 'category'
}
}
};
Then query from category would be
Category
.find()
.where({ name: query })
.populateAll()
.exec(function (error, categories) {
var catArr = [];
if (categories.length) {
categories.map(function (item) {
catArr.push(item.id);
});
}
Post.find().where({ category: catArr }).exec(function (error, posts) {
// do stuff
});
});
Or simply you can query it from post by
Post
.find()
.where({ category: categoryId })
.populateAll()
.exec(function (error, posts) {
// posts is all post with category that defined
});
Make sure that you know categoryId if you want to query it from post. I usually use categoryId is string and slugify from name, so I can query category by it's name and make sure that category name (and also ID of course) is unique.
Figured how to implement this using the category id:
Category.find().where({ name: query }).exec(function (error, categories) {
var catArr = [];
if (categories.length) {
categories.map(function (item) {
catArr.push(item.id);
});
}
Post.find().where({ category: catArr }).exec(function (error, posts) {
// do stuff
});
});
Also had to add attributes in the models like so:
// Post
module.exports = {
attributes: {
name: {
type: 'string'
},
category: {
model: 'category'
}
}
};
// Category
module.exports = {
attributes: {
name: {
type: 'string'
},
post: {
model: 'post'
}
}
};

Categories

Resources