I'm using denormalization to manage posts in a blog, so I used to embed the documents as showing below
the problem is that I don't know the way to manage documents in subdocument of subdocument
const Post = new Schema({
title:{type:String,required:true,minLength:5},
description:{
type:String,
required:true,
minLenghth:15
},
createdAt:{type:Date,default:Date.now},
author:{type:mongoose.Types.ObjectId ,ref:'users'},
authorName:String,
authorImage:{type:String ,default:"none"},
comments:[
{
author:{type:mongoose.Types.ObjectId,ref:'users'},
authorName:String,
text:{type:String,minLength:1},
createdAt:{type:Date,default:Date.now},
likes:[
{
author:{type:mongoose.Types.ObjectId ,ref:'users'},
createdAt:{type:Date,default:Date.now}
}
]
}
],
likes:[
{
author:{type:mongoose.Types.ObjectId ,ref:'users'},
createdAt:{type:Date,default:Date.now}
}
]
})
and I wanted to add like to comment .
Thanks for any help. Moataz
based on postId and commentId find the document, after that push your object in likes field
await Post.findOneAndUpdate(
{
_id: postId,
'comments._id': commentsId,
},
{$push:{
"comments.$.likes" : {author : id}
}}
);
Related
I can't push items into MongoDB array every time that i try to push a new element it creates an empty object and i cant figure out why,
I already used the
Collection.Array.push({element})&
Collection.save()
but i cant figure out a solution
This is My Schema
const Schema = mongoose.Schema;
var ParticipantSchema = new Schema({
nom:{Type:String},
prenom:{Type:String},
email:{Type:String}
})
var CompetitionSchema = new Schema({
nom:String,
date:Date,
place:String,
participant :[ParticipantSchema]
})
module.exports = mongoose.model("Competition",CompetitionSchema);
This is my funtion
exports.addParticipant=function(req,res){
var newParticipant={
"nom":req.body.nom,
"prenom":req.body.prenom,
"email":req.body.email
}
Competition.updateOne(
{ _id:req.body.id},
{ $push: { participant: newParticipant } },
(err,done)=>{
return res.json(done)
}
);
}
the result is always an empty object like below
{
"_id": "5ded0eeb85daa100dc5e57bf",
"nom": "Final",
"date": "2019-01-01T23:00:00.000Z",
"place": "Sousse",
"participant": [
{
"_id": "5ded0eeb85daa100dc5e57c0"
},
{
"_id": "5dee3c1b08474e27ac70672e"
}
],
"__v": 0
}
There is no problem in your code, the only problem is that in schema definition you have Type, but it must be type.
If you update your ParticipantSchema like this, it will work:
var ParticipantSchema = new Schema({
nom: { type: String },
prenom: { type: String },
email: { type: String }
});
You are using another Schema in the Array. This results in so-called subdocuments (https://mongoosejs.com/docs/subdocs.html). Mongoose does not populate subdocuments by default. So all you see is just the _id. You can use the populate method to see all subdocuments in detail. ( https://mongoosejs.com/docs/populate.html ) .
Example :
Competition.
find({}).
populate('participant').
exec(function (err, comps) {
//
});
You can either use populate on the Model or on the Document. For populating a document, take a look at https://mongoosejs.com/docs/api.html#document_Document-populate . There is also a auto-populate plugin available via npm but in most cases it's not necessary : https://www.npmjs.com/package/mongoose-autopopulate .
I have a simple embedded document:
{
"username":"user001",
"name":"John",
"tasks":[
{
"id":0,
"title":"Candy",
"description":"Lots of candy for you",
"category":"food",
"cost":2500,
"candyTypes":[
{"name":"gum", "type":"sweet", "price":"2"},
{"name":"chocolate", "type":"tasty", "price":"3"}
]
}
]
}
When I try to query the task data through the mongo shell, I get everything:
db.users.findOne({ 'username': 'user001', 'tasks.id':4 }, {'tasks.$':1})
/* returns */
"tasks":[
{
"id":0,
"title":"Candy",
"description":"Lots of candy for you",
"category":"food",
"cost":2500,
"candyTypes":[
{"name":"gum", "type":"sweet", "price":"2"},
{"name":"chocolate", "type":"tasty", "price":"3"}
]
}
]
But when I try to do the same in mongoose, the candyTypes array comes back empty:
Users.findOne({ 'username': username, 'tasks.id':taskId }, {'tasks.$':1}, function (err, data) {
console.log(data);
});
/* returns */
"tasks":[
{
"id":0,
"title":"Candy",
"description":"Lots of candy for you",
"category":"food",
"cost":2500,
"candyTypes":[]
}
]
I'm pretty new to MongoDB and Mongoose, but after searching and looking through documentation, I can't figure out what I'm missing.
UPDATE
I couple users requested it, so here is my mongoose schema:
var UserSchema = new mongoose.Schema({
username:String,
name:String,
tasks:[{
id: Number,
title: String,
description:String,
category: String,
cost: Number,
candyTypes:[{
title:String,
type:String,
value:String
}]
}]
});
With Mongoose, you have to populate candyTypes array:
Users.findOne({ 'username': username, 'tasks.id':taskId }, {'tasks.$':1})
.populate('candyTypes')
.exec(function (err, data) {
console.log(data);
});
See docs: http://mongoosejs.com/docs/populate.html
I think it's related to you declaring a field called type which also has a special meaning in Mongoose, namely to signify the type of a field.
If you rename that field to something else (candyType), it'll probably work better.
Alternatively, you can use the typeKey option to make Mongoose use a different property name to signify field type.
As an aside, your document contains a field price but your schema names it value.
I am using mongoose for connecting mongodb in node.js, now i have a document schema as given below
var ArraySchema = new Schema({
array: [{type: String}],
counter: {type: 'Number', required: true}
});
Now i want to fetch array element whose position is counter which is present in the document as well, i read many questions like this on SO and on most of them i found mongoose aggregation but i don't know how to use aggregation to solve my problem.
If anyone of you have used aggregation please help me.
Use this query in my mongoose.
var aggregation = [
{
$project : {
array : {$arrayElemAt: [ "$array", "$counter" ] }
}
}]
db.collectionName.aggregate(aggregation).exec(function(err, model){
if(err){
// handle error}
console.log(model);
})
you can do this with this query:
db.pos.aggregate([
{
$project:{
result:{
$arrayElemAt:[
"$array",
"$counter"
]
}
}
}
])
I'm creating a Post & Comments, and I designed to post contains comments. "Comments" is embedded document(Object Array) field that contains comment information, and uses "_id" as unique identifier. This is the code(Note that I'm using Node.js with extra mongoDB library) :
db.update('posts', {
_id: new ObjectID(postId)
}, {
$push: {
comments: {
_id: new ObjectID(),
author: comment.author,
email: comment.email,
text: comment.text
}
}
}) ...
Look at the $push, you can see that I created new ObjectId. It's working well, but I want to send back the _id that just created comment to the client, so make client can erase or edit without page refresh. How do I get the _id that just created embedded document?
How about setting them to variables when you create the ids:
const id1=new ObjectID(postId);
const id2=new ObjectID();
db.update('posts', { _id: id1 },
{ $push:
{ comments: { _id: id2,
author: comment.author,
email: comment.email,
text: comment.text } } }) ...
Schema of group and member are as below:
var group=new Schema({
group_id:Number,
group_name:String,
members:[member]
});
var member=new Schema({
member_id:number,
name:String,
});
Sample document after inserting some record in group collection
[{
_id:55ff7fca8d3f6607114dc57d
group_id:1001,
group_name:"tango mike",
members:[
{
_id:44ff7fca8d3f6607114dc21c
member_id:2001,
member_name:"Bob martin" ,
address:String,
sex:String
},
{
_id:22ff7fca8d3f6607114dc22d
member_id:2002,
member_name:"Marry",
address:String,
sex:String
},
{
_id:44ff7fca8d3f6607114dc23e
member_id:2003,
member_name:"Alice" ,
address:String,
sex:String
}
]
}]
My problem:
I am trying to update record of individual group member(element of subdocument members). While updating I have follwing data group: _id, group_id, members:_id and newdata. I am trying like this; but it is not working
var newData={
member_name:"Alice goda" ,
address:"xyz",
sex:"F"
}
groupModel.findOne({"_id":"55fdbaa7457aa1b9bd7f7cf7","group_id":1001},'members -_id',function(err,groupMembers){
if(err)
{
res.json({
"isError":true,
"error":{
"status":1042,
"message":err
}
});
}
else
{
var mem=groupMembers.id("44ff7fca8d3f6607114dc23e");
mem.member_name=newData.member_name;
mem.address=newData.address;
mem.sex=newData.sex;
mem.save(function(err,data){
if(!err)
//sucessfull updated
});
res.json(groupDetails);
}
});
As I understand from your question details, you would like to update one object from the members array, in accordance with the criteria that you specify.
Thus, in order to accurately run the update query for your use case, you could run the following update operation against your collection:
db.collection.update({ _id: "55ff7fca8d3f6607114dc57d",
group_id:1001,
members: {
$elemMatch: { _id: "44ff7fca8d3f6607114dc23e" }
}
},
{ $set: {
"members.$.member_name": "Alice goda",
"members.$.address": "xyz",
"members.$.sex": "F"
}});
Still, be aware that the $ positional operator only updates the first array item that matches your query.
Unfortunately, there is no possibility of updating all the array elements that match your criteria in a single operation. As you can see on MongoDB Jira, the aforementioned feature is one of the most requested functionality, but it has not yet been directly implemented in MongoDB.