Not sure how to save in MongoDB - mongodb

I am trying to push to a sub-collection for a MongoDB and I am not sure how to go about it.
So, my post collection structure:
{
"_id": "58a3189b67476b420e465f8b",
"postID": "123456",
"comments": [
{
"subComments": [],
"comment": "This is a test",
"commentID": 1
}
]
}
So, what I want to do is find the above document using findOneAndUpdate and then select this particular comment (commentID == 1), and then push into the subComments of it.
I can see how you can findOneAndUpdate by it's postID and add comments by pushing in Mongoose but how do I find the post, and then the comment by it's commentID and then push into it's subComment?
Thanks in advance guys! Very stuck on this last piece of the puzzle.

It's similar to other find queries.
You can try this:
Post.findOneAndUpdate({
"postID" : givenPostID,
"comments.commentID" : givenCommentID
},{
$push : {
"comment.$.subComments" : givenSubComment
}
},function(err,result){...});
comments.commentID: givenCommentID will find the comment element with commentID == givenCommentID.
comment.$.subComments will push givenSubComment to the subComments array of the matched element of the comments array (matched based on commentID).
For more information Please read MongoDB $(update) operator documentation.

Related

Index and sort on nested variable field MongoDB

I have a document that looks like this :
{
"_id": "chatID"
"presence": {
"userID1": 1647627240464,
"userID2": 1647227540464
},
}
I need to query for each userID the chats where he is present and order by the timestamp in the presence map.
I am aware that this is probably not the best way to do, before i had 1 element per user meaning duplicating the chatIDs, but it's a pain to update them all because it would look like :
{
"_id": "userID1chatID",
"at": 1647627240464,
"ids": "30EYwO01_Nyq7dMqe_O3vfL3AH",
"members": ["userID1", "userID2", "userID3"],
"owner": "userID1",
"present": true,
"uid": "chatID",
"url": "databaseURL"
}
This would allow me to find the chats where userID1 is present: true and order by at DESCENDING.
The problem with this is that i need to update the at attribute for all the documents (one per user) for this same chat room.
How can i do this same query while maintaining a single document with present as a map ?
Problem : the index would be on a variable : userID1, userID2, etc...
like : present.userID1 and seems to not be convenient for use when userID1 can be removed from the present map if the user leaves the chat.
Please let me know if this is unclear, thanks in advance.

Mongo - request all embedded comments in Post query

I'm adapting the Microscope tutorial to my needs and am having difficulty writing a query which gathers all the comments embedded within a post.
Here is my query so far:
Posts.find({"postId": this._id}, {"comments":{}});
Here is an example post I want to get the comments from:
{
"_id": "Ad9RYqWqbsJKZx3h7",
"title": "Writing decimal number words as a decimal number",
"userId": "9yqTaFeQSqvKmNn8B",
"author": "Sacha Greif",
"submitted": "2017-01-05T03:26:18.908Z",
"commentsCount": 4,
"comments": [
{
"body": "Hello",
"postId": "Ad9RYqWqbsJKZx3h7",
"userId": "73qGvsRuqNtXcaZDx",
"author": "student",
"submitted": "2017-01-05T10:26:45.745Z"
},
{
"body": "How are you?",
"postId": "Ad9RYqWqbsJKZx3h7",
"userId": "73qGvsRuqNtXcaZDx",
"author": "student",
"submitted": "2017-01-05T10:28:17.225Z"
}
]}
It seems to return a cursor, but I am not able to use the toArray() function on it.
I have read this is not possible (Filtering embedded documents in MongoDB), but this was six years ago...
I've also seen posts about $slice and aggregate but can't seem to get me head around them.
Any help much appreciated!
query this->
Posts.find({"comments.postId": this._id});
You can just simply use findOne to get the specific document from the collection and you can use forEach Loop to iterate through the comments array of that document.
var post = Posts.findOne({_id: "<id_of_the_post>"});
var post_comments = post.comments; // post_comments contains the comments array
or if you want to do something with each comment use forEach
post_comments.forEach(function(entry, index, arr){
// entry has the comment object
//do something with the comment
});
I hope this helps.

MongoDB - Meteor : Update, add and delete an element from an array

I am trying to select a specific element in an nested array in a hash like so.
post:{
_id,
comments:[{
comment_id:post.comments.length + 1,
comment: "hello world",
user_id:Meteor.userId()}]
}
My ultimate goal is to be able to add/edit/delete the nested comment by comment_id but I am having trouble trying to select the element I need in the first place.
If you only have comments in your post object you should only have a comments array like this:
Posts {
_id: String;
comments: [];
}
And to delete a comment by his id :
Posts.update({_id: postId, "comments.comment_id" : "commentIdToDelete"},
{ $pull:{"comments": {"comment_id": "commentIdToDelete"}}})
To update a comment by his id :
Posts.update({_id: postId, "comments.comment_id" : "commentIdToUpdate"},
{ $set:{"comments.$.comment": "A new comment"}})
UPDATE
In order to add a comment in the comments array we have to initialiaze the post document (if it's not already done):
Posts.insert({
comments: []
});
Now we have to retrieve the comments array size of the post to update:
let lengthComments = Posts.findOne({_id: postIdToUpdate}).comments.length;
And finally we can add a comment in the comments array:
Posts.update({_id: postIdToUpdate}, {
$push: {
"comments": {
"comment_id": lengthComments + 1,
"comment": "My comment",
"user_id": Meteor.userId(),
}
}
});

Mongodb: Update a field with data from a sub-sub field?

I'm trying to update a field in a collection with data from the same collection, but from a sub-sub field in it, and either can't get the syntax right, or I'm just doing it wrong.
I've spent quite some time now digging around here, but can't seem to get anywhere.
Here's the example structure of the users collection:
{
"_id": "12345qwerty",
"services": {
"oauth": {
"CharacterID": 12345678,
"CharacterName": "Official Username",
},
},
"name": "what I want to change",
"username": "OfficialUsername"
}
What I'm trying to do would be pretty trivial with SQL, ie: update all the display names to match a trusted source...
update users
set name = services.oauth.CharacterName;
...but I'm having trouble getting in MongoDB, and I have a feeling im doing it wrong.
Here's what i have so far, but it doesn't work as expected.
db.users.find().snapshot().forEach(
function (elem) {
db.users.update(
{ _id: elem._id },
{ $set: { name: elem.services.oauth.CharacterName } }
);
}
);
I can set the name to be anything at the base level, but can't set it to be something from the sublevel, as it doesn't recognise the sub-fields.
Any help would be greatly appreciated!
db.users.update({"services.oauth.CharacterName": {$exists: true}},{$set: {"name": "services.oauth.CharacterName"}},{multi:true})
I am setting name at the root of your document to be equal to the value in services.oauth.CharacterName in the sub sub document. multi = true will update multiple document, I am only updating documents that have the services.oauth.CharacterName value.

Move subdocument to another document

I'm modelling a mongodb database that will have categories and articles.
The most common use will be listing articles through the categories, so I plan to make the articles as subdocuments of categories:
//db.categories.find()
[{
"id": 01,
"name": "Some category",
"articles: [{
"article_id": 01,
"title": "",
"content": ""
}]
}]
Sometimes, I might be moving articles from one category to another.
In a relational database, I should just update a foreign key, but in the above case, how can I move an article to another category?
Some details:
Preferable, the internal ObjectId should remain the same. But it's not mandatory.
Article might also contain subdocuments, if so, they must come along when moving.
You need first to get the article, then remove (pull) the article from its current category and then add (push) it into its new category, like this:
first get the article (article_id:01) from the category with id:01 ...
then pull the article with article_id:01 from the category with id:01
db.categories.update(
{"id" : 01, "articles.article_id" : 01}, // query
{"$pull" : {"articles" : {"article_id" : 01}}} // pull
)
and then push that same article (article_id:01) into its new category with id:02,
db.categories.update(
{"id" : 02}, // query
{"$push" : {"articles" : { // push
"article_id": 01,
"title": "",
"content": ""
}
}
}
)
if you want the array in the new category to be sorted after the push you have to use $each and $sort (see here).
For more info on $pull check here and for more info on $push check here.