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 } } }) ...
Related
Hello beautiful community. Hope you guys are doing okay.
So I'm working on this app where I have two MongoDB collections, Posts and CommentsView.
Posts collection consists of post title, post type and their comments. The comments is an array of objects that consists of how many times each comment is viewed and the id.
In the CommentsView collection, I intend to store all the comments when they are viewed. Duplicates is not a problem.
Here's how the schema looks like:
Posts Schema:
const postsSchema = new mongoose.Schema( {
postTitle: {
type: String
},
comments: [ {
totalViews: {
type: Number
},
uid: {
type: String
}
}],
postId: {
type: String
}
} );
CommentsView Schema:
const commentsViewSchema = new mongoose.Schema( {
text: {
type: String,
},
uid: {
type: String
}
} );
Suppose I have a post with two comments with uid 'A' and 'B' respectively. Whenever the comment with uid 'A' is viewed, I will create a comment in CommentsView collection. And automatically add 1 view in Posts collection's totalView field. When the same comment is viewed again, I will first add it in CommentsView collection then increment totalView field in Posts collection.
Suppose I have these documents in Comments collection:
{
text: 'Life is good',
uid: 'A'
},
{
text: 'Boom Boom',
uid: 'B'
},
{
text: 'Bam Bam',
uid: 'A'
},
So the Posts document will look like this:
{
postTile: '60 seconds to Mars',
comments: [
{
uid: 'A',
totalViews: 2,
},
{
uid: 'B',
totalViews: 1,
},
],
postId: '1s93njs'
}
I have not tried anything yet as I have no idea where to start. It seems so complicated.
How can I achieve this if I want the whole process to be automatic?
Since you are using two different schema, I recommend you to use references,
beacause if you want to add more features like number of likes and threads then this model suggested below will be useful
Don't use String type for storing Id's of the model use the type ObjectId provided by the mongoose module.
Post Model
const postsSchema = new mongoose.Schema( {
postTitle: {
type: String
},
comments: [
type:ObjectId,
ref:"model name"
],
postId: {
type: String
}
}, {timestamps:true});
Comment Model
const commentsViewSchema = new mongoose.Schema( {
text: {
type: String,
required:true
},
totalView:{
type: Number,
default:0
}
},{timestamps:true} );
now each time a post is viewed you can search for the commment id and increment the count in the document. and everything will be reflected in the post model if you populate all the comments in the array
Example
work flow
User Viewed the comment-->(getcomment_id) --> update the comment
Now all subsequent request for the post with this comment will also have the updated view because of reference.
query to update the comments
comment.findByIdAndUpdate({_id:<comment_id>}, {$inc:{totalView:1}})
other way is to have embedded do, I recommend this if you think there won't be much comments for the posts, otherwise having the above model is good.
you can further refer to these articles
rules to follow for designing mongodb schema
Hope this helped you get a good idea
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}
}}
);
I'm using this code for removing a particular array element stored in MongoDB when clicked that from the app. But this code is not working.
schema structure looks like this -
const tagsSchema = new Schema({
category: {
type: String,
required: true
},
tname: { type: Array }
}, { _id: true });
Below is the code I'm using for removing array element from db -
Tags.updateOne({ tname: req.params.name }, { $pull: { _id: [req.params.id] } })
For example - "tname": "technical", "nontechnical"
Now, technical is being clicked in the app to remove, but with the code I'm using it's not getting removed.
you can use directly your element_value without [] after your array field, like below..
Tags.updateOne({tname: req.params.name}, { $pull: { your_array_field: req.params.id } } )
You have to find the specific tag by its "_id" and then remove the particular name from the "tname" array.
Tags.updateOne({ _id: req.params.id }, { $pull: { tname: req.params.name } })
I'm designing a backend for a Talent hunt application. Initially I designed the DB using refs. Like I followed the primary key forign key using refs to join my collections. But as the collection requirement increases it's being hard to join all the collections. Then I come across the one to many collections. So I'm thinking to get a suggestion from experts. Let me tell the requirements.
I have the following collections initially.
User.js
{
_id: "5ecfdc903165f709b49a4a14",
name: "Lijo",
email: "lijo#gmail.com"
}
then I have a category table for serving the categories
Category.js
{
_id: 5ecfdc903165f709b49a5a18,
title: "Acting",
code: "ACT"
}
If one user adds his talents to profile. I used one another collection for storing. Rmember the user can save multilple talents. So i created,
UserTalents.js
{
_id: "5ecfdc903165f709b49a6c87",
categoryId: "5ecfdc903165f709b49a5a18",
userId: "5ecfdc903165f709b49a4a14",
level: "beginner"
}
For each catgeory need to upload atleast one media along with description Soagain I created a new collection for that.
Media.js
{
_id: "5ecfdc903165f709b49a8a14",
talentId: "5ecfdc903165f709b49a6c87",
userId: "5ecfdc903165f709b49a4a14"
media: "5ecfdc903165f709b49a4a14_1.jpg"
}
And I need to have these users connected. For that craeted.
Friends.js
{
_id: "5ecfdc903165f709b49a8a18",
sender: "5ecfdc903165f709b49a4a14",
receiver: "5ecfdc903165f709b49a4a15"
status: "accepted"
}
Is this good to continue??? Expecting a huge amount of users. Or can I follow like:
User.js
{
_id: "5ecfdc903165f709b49a4a14",
name: "Lijo",
email: "lijo#gmail.com",
talents: [
{
_id: "5ecfdc903165f709b49a5a18", // _id from Category
title: "Acting",
code: "ACT",
level: "beginner",
media: "5ecfdc903165f709b49a4a14_1.jpg"
}
],
friends: [
{
_id: "5ecfdc903165f709b49a4a15",
name: "Test",
status: "approved"
}
]
}
I I follow this, then how do I update the name fileds in talents and friends array either one of its original name is changed?
Which is better approach?
i have a mongo collection that looks like this:
{
name: string
_id: (auto set)
items: array[
name: string
url: string
items: array[
{
name: string,
url: string,
items: []
}
]
]
}
I'm using findByIdAndUpdate (with mongoose) to add an item into the items array:
Menu.findByIdAndUpdate(
req.body.parentid,
{
$push: {
items: {
name: req.body.item.name,
url: req.body.item.url,
items: []
}
}
},
{
safe: true,
upsert: true,
new: true
},
function(err, model) {
if (err !== null) {
console.log(err);
}
}
);
This works fine, but it does not add an _id to each object inserted into the items array. And i really need an id for each one.
I'm guessing it comes from the method used, findByIdAndUpdate as it looks more like an update rather than an insert. If my thinking is correct.
Using mongodb 3.2.10 and mongoose 4.7.6.
Any help would be really appreciated.
Thanks.
EDIT: the _id: (auto set) is not real, it's being automatically added via mongo. But just at the top level objects.
Found the solution in this thread: mongoDB : Creating An ObjectId For Each New Child Added To The Array Field
basically, added
var ObjectID = require('mongodb').ObjectID;
and then forcing the creation:
$push: {
items: {
_id: new ObjectID(),
name: req.body.item.name,
url: req.body.item.url,
items: []
}
}
You dont need to sepcify _id: (auto set) in mongoose schema it will automatically add unique _id with each document.
if you don't define _id in Schema, mongoose automatically add a _id to array item.
for example:
const countrySchema = new Schema({
name: {
type: String
},
cities: [
{
// don't define _id here.
name: String
}
],
});
now when you insert a row, the result is something like this:
{name : 'Iran', cities : [{_id : 6202902b45f0d858ac141537,name :
'Tabriz'}]}