I have a mongoose schema that looks like this, that I am able to update and query just fine:
// Subscriber Schema
var Subscriber = new Schema({
'user': ObjectId,
'level': { type: String, enum: [ 'sub', 'poster', 'blocked' ] }, //blocked means users has opted out of list
'dateAdded': { type: Date, default: Date.now }
});
// Group Schema
var Group = new Schema({
'groupEmail': { type: String, lowercase: true, validate: [validatePresenceOf, 'an email is required'], index: { unique: true } },
'groupOwner': ObjectId,
'groupName': String,
'twitterFeed': String,
'subscribers': [Subscriber],
'createdAt': { type: Date, default: Date.now }
});
I'm trying to update a Subscriber within the Group document, and change its level, then save the change. I'm able to find the group just fine using:
Group.findOne({ _id: req.params.groupId }, function(err, g)
Once I have the group, I want to find a subscriber so I can update it. If I try:
g.subscribers.update({ 'user': req.params.userId }, { level: newStatus });
I get:
TypeError: Object { user: 4fc53a71163006ed0f000002,
level: 'sub',
_id: 4fd8fa225904a5451c000006,
dateAdded: Wed, 13 Jun 2012 20:37:54 GMT },{ user: 4fda25ac00cd9bdc4f000004,
level: 'sub',
_id: 4fda270bbce9f8d058000005,
dateAdded: Thu, 14 Jun 2012 18:01:47 GMT },{ user: 4fda2a634499dfd16e00000d,
level: 'sub',
_id: 4fda2a634499dfd16e00000e,
dateAdded: Thu, 14 Jun 2012 18:16:03 GMT } has no method 'update'
I've tried various permutations of update, find, etc. but always get the "has no method" error. What am I doing wrong? Is there a different way I should be updating Subscriber.level?
Thanks!!
#eltoro is mostly correct, arrays do not have an update method, and the suggestion to use Group.update is a good one, but the update syntax is missing the $ in subscribers.$.level.
Group.update(
{_id: req.params.groupId, 'subscribers.user': req.params.userId},
{ 'subscribers.$.level': newStatus }, function(err, result) {}
);
I think you're getting the error because you're calling update on the instance instead of the model.
Maybe try something like this:
Group.update(
{_id: req.params.groupId, subscribers.user: req.params.userId},
{ subscribers.level: newStatus }, function(err, result) {}
);
Related
I have 2 mongo schemas related one with the other using ObjectId:
var User = new Schema({
username: {
type:String,
unique: true
},
password: {
type:String
},
verified: {
type: Boolean,
default: false
},
lastActivity:{
type:Date,
default:Date.now
}
});
And a watitingRoom schema with lists all the users:
var WaitingRoom = new Schema({
lastActivity:{
type:Date,
default:Date.now
},
clients: [{
type : mongoose.Schema.ObjectId,
ref: 'User'
}],
videocalls: [{
type: mongoose.Schema.ObjectId,
ref:'VideoCall'
}]
});
So, I want to 'refresh' my clients array pulling all the clients which a lastActivity less than the current time. I tried it by using the $pull tool present in mongoose. After googling and mixing different examples I tried things like:
WaitingRoom.findOneAndUpdate({}, { lastActivity: new Date(),
$pull : {clients : {"clients.lastActivity": { $lt: new Date() }}}
}, options)
.populate("clients")
.exec( function(error, waitingRoom) {
if (err) { return res.status(500).send({ msg: err.message }); }
})
Which finds the unique waiting room, updates the lastActivity field and tries to pull all the clients that has a clients.lastActivity less than the current date.
(Obviously this snipped code doesn't work)
The problem is that I didn't find any documentation or example that explains if it is possible to pull elements from a referred ObjectId schema using a nested condition clients.lastActivity
You need to first find the ids from User database and then need to $pull them from the WaitingRoom database
User.find({ lastActivity: new Date() }).then((users) => {
const ids = []
users.map((user) => {
ids.push(user._id)
})
WaitingRoom.update({}, { $pull: { clients: ids }}, { multi: true }).then(() => {
console.log('removed')
})
})
I have a schema:
var userSchema = new Schema({
name: String,
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
admin: Boolean,
created_at: Date,
updated_at: Date
});
Let's assume I have made 100 Users using this schema.
Now I want to change the schema:
var userSchema = new Schema({
name: String,
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
admin: Boolean,
created_at: Date,
friends: [Schema.Types.ObjectId], //the new addition
updated_at: Date
});
I need all new Users to have this field. I also want all of the 100 existing Users to now have this field. How can I do this?
You can use Mongoose Model.update to update all your documents in the collection.
User.update({}, { friends: [] }, { multi: true }, function (err, raw) {
if (err) return handleError(err);
console.log('The raw response from Mongo was ', raw);
});
I don't recommend to do it in production if the collection is big, since it is a heavy operation. But in your case it should be fine.
Using the query interface in a client app or your terminal you could do:
db.users.updateMany({
$set: { "friends" : [] }
});
Here's the docs reference.
it doesn't work for me :x
Here is my code
let test = await this.client.db.users.updateMany({
$set: { "roles" : [] }
});
and the output
{ ok: 0, n: 0, nModified: 0 }
I don't know how to do, i tried a lot of things and uh it doesn't work :'(
EDIT: I found, here is my code
await this.client.db.users.updateMany({ }, [ {$set : { "roles": []} } ]);
I have a model with nested object and I want to update single field of that document but unable to do it. I could not understand why it's not working.
This is my model
var sampleItemSchema = new Schema({
id: {
type: String,
required: true
},
content: {
type: Object,
required: true
},
location: Object,
createdAt: {
type: Date,
default: Date.now
},
sample: {type: mongoose.Schema.Types.ObjectId, ref: 'Sample'}
});
And this is my one of document.
{ createdAt: Thu Apr 21 2016 19:46:17 GMT+0200 (CEST),
__v: 0,
sample: 571911df9a97810c3f35d83d,
location: { city: 'Kildare' },
content:
{ images: [],
price: { currency: 'EUR', amount: 2000 },
createdAt: '2016-04-21T17:46:17.349Z',
category: { id: '2012', name: 'Animals | Ponies' },
body: 'Beaulieu Ginger Pop (Ben) is a 14 year old 13.2hh grey roan New Forest pony. He has a full green passport, is microchipped and is fully up...',
title: '13.2hh All rounder Gelding' },
id: '12123191',
_id: 571911e99a97810c3f35d845 }
Here what I tried yet.
I am just giving part of code
models.SampleItem.find({
sample: sample
}, function(err, sampeItemList) {
console.log('Total sample: ', sampeItemList.length);
async.eachSeries(sampeItemList, function(item, next) {
item.content.body = "want to update this field";
item.save(function(err, updatedItem) {
console.log('Updated description...', index);
})
})
})
Am I doing something wrong?
Mongoose does not allow you to use Object as a schema type. Instead set the type to Schema.Types.Mixed. This will give you an object with whatever properties you want to set.
You can see the list of all the valid schema types in the Mongoose Schema Types documentation.
(You probably want to change the location field to Schema.Types.Mixed as well.)
Mongoose doesn't allow 'Object' as a type. Use 'Schema.Types.Mixed' for properties which have flexible/unknown values.
From the documentation for toObject it states that the minimize option will remove empty objects (defaults to true)
and also the documentation for toJSON states this method accepts the same options as Document#toObject.
However I have noticed two instances where this doesn't appear to be true (I haven't done an exhaustive check yet).
My main question is: Am I missing something (this is the intended output) or is this a bug?
Using version 3.8.7.
Given the simple schemas:
var CommentSchema = mongoose.Schema({
body: String,
created: {
by: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
}
});
var BlogSchema = mongoose.Schema({
title: String,
blog: String,
created: {
by: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
},
comments: [CommentSchema]
});
var Blog = mongoose.model('Blog', BlogSchema);
Case 1
Blog.findOne({
_id: id
}, function(err, blog) {
console.log(blog); // causes toJSON to be executed
});
// outputs:
{
title: 'My first blog! #Super',
blog: 'This is my very first #blog! I hope you enjoy it. #WOOHOO',
_id: 532cb63e25e4ad524ba17102,
__v: 0,
comments: [], // SHOULD THIS BE INCLUDED??
created: {
by: 'Joe',
date: Fri Mar 21 2014 17: 59: 26 GMT - 0400(EDT)
}
}
Case 2
Blog.findOne({
_id: id
}, 'title', function(err, blog) {
console.log(blog); // causes toJSON to be executed
});
// outputs:
{
title: 'My first blog! #Super',
_id: 532caa3841176afb4a7c8476,
created: {} // SHOULD THIS BE INCLUDED??
}
First, my understanding for forcing toJSON by using console.log was incorrect. To do so use: console.log(JSON.parse(JSON.stringify(blog)));
Using the correct method to show the JSON representation of the mongoose document solves case #2:
Blog.findOne({
_id: id
}, 'title', function(err, blog) {
console.log(JSON.parse(JSON.stringify(blog))); // causes toJSON to be executed
});
// outputs:
{
title: 'My first blog! #Super',
_id: 532caa3841176afb4a7c8476
}
However, the empty array from case #1 is still returned:
Blog.findOne({
_id: id
}, function(err, blog) {
console.log(JSON.parse(JSON.stringify(blog))); // causes toJSON to be executed
});
// outputs:
{
title: 'My first blog! #Super',
blog: 'This is my very first #blog! I hope you enjoy it. #WOOHOO',
_id: 532cb63e25e4ad524ba17102,
__v: 0,
comments: [], // SHOULD THIS BE INCLUDED??
created: {
by: 'Joe',
date: Fri Mar 21 2014 17: 59: 26 GMT - 0400(EDT)
}
}
So I guess the answer is if the documentation means only empty objects (and not arrays) than this is expected behavior.
Having a problem with like removal
My schema
/**
* Article Schema
*/
var Comments = new Schema({
body: { type : String, default : '' },
user: { type : Schema.ObjectId, ref : 'User' },
createdAt: { type : Date, default : Date.now }
})
var Likes = new Schema({
user: { type : Schema.ObjectId, ref : 'User' },
createdAt: { type : Date, default : Date.now }
})
var ArticleSchema = new Schema({
title: {type : String, default : '', trim : true},
body: {type : String, default : '', trim : true},
geo: {type: [Number], set: setTags},
user: {type : Schema.ObjectId, ref : 'User'},
comments: [Comments],
likes: [Likes],
tags: {type: [], get: getTags, set: setTags},
image: {type:String, default : ''},
createdAt : {type : Date, default : Date.now}
})
And I want to make like/unlike functionality, adding like works but removing simply doesnt change the document.
Controller:
exports.like = function (req, res) {
var article = req.article
var user = req.user
Article.getArticleByWithLikesByUserId(req.user.id, function(err, articles) {
console.log(articles);
if(!articles.length){
console.log('adding like',new Date);
article.addLike(user, function (err) {
if (err) return res.render('500')
res.redirect('/articles/'+ article.id)
});
}
else{
console.log('removing like',new Date);
article.removeLike(user, function (err) {
if (err) return res.render('500')
res.redirect('/articles/'+ article.id)
});
}
});
schema methods:
addLike: function (user, cb){
this.likes.push({
user: user._id
})
this.save(cb);
},
removeLike: function (user, cb){
var that = this;
this.likes.forEach(function(like, index) {
if(like.user == user.id){
var newLikesObj = that.likes.toObject();
console.log("before splice:\n ",newLikesObj);
newLikesObj.splice(index,1);
console.log("after splice: \n",newLikesObj);
that.likes = newLikesObj;
that.save(cb)
}
});
and from logs splice seems to be working ok
before splice:
[ { user: 5247095b5696e45c2b000102,
_id: 524defc87153550829000103,
createdAt: Fri Oct 04 2013 01:29:28 GMT+0300 (Финляндия (лето)) },
{ user: 5247095b5696e45c2b000002,
_id: 524df3c2a663050805000003,
createdAt: Fri Oct 04 2013 01:46:26 GMT+0300 (Финляндия (лето)) } ]
after splice:
[ { user: 5247095b5696e45c2b000102,
_id: 524defc87153550829000103,
createdAt: Fri Oct 04 2013 01:29:28 GMT+0300 (Финляндия (лето)) } ]
static method:
getArticleByWithLikesByUserId: function (id, cb) {
this.find({ 'likes.user' : id })
.populate('user', 'name email username')
.populate('comments.user')
.exec(cb)
}
I've also tried this update method, still doesnt remove like even though numberAffected is showing 1
this.update({$pull : {'likes.user':user.id}}, function(err, numberAffected){
if(!err){
return console.log('like removed');
} else {
return console.log(err);
}
});
I can't say what's going wrong with your example, other than that you're going about it the wrong way. MongoDB provides an an easier, built in way to remove items from an array either by specifying the exactly, or via a query:
Behold the $pull operator.
In mongoose one way to do this would be:
Article.findByIdAndUpdate(this._id, {
$pull: {
likes: {user: user._id}
}
}, cb);