group and collect document based on field in mongodb - javascript

I have notifications collection with this schema
_const notificationsSchema = new Schema({
_from: {
type: Schema.ObjectId, ref: 'User',
},
_to: {
type: Schema.ObjectId, ref: 'User',
},
_target: String,
type: {
type: String,
},
createdAt: {
type: Date,
default: Date.now,
},
});
How to group notifications like facebook " and 50 others liked your post"?
How to retrieve this shape of data, for the documents that has same _parent?
[
{
_id: "",
_to: "",
_parent: "",
lastThreeUsers: [_ from, ...],
count: 50
}
]

This is a very open ended response. There is no one right answer. I have provided both a naive and ideal approach to the problem. You may think of another, better way.
You would need to have a something along the lines of a "Likes" collection where you store all likes from users where each like has a reference to the post being liked. Then you would have to perform an aggregation on the likes collection to get all the likes where the postId is equal to the id of the post you want total likes for.
First attempt that.
Then a better, "real world" approach is to also add a "likesCount" (call it what you want) property onto Post documents that keeps tracks of the likes on the post. Update the likesCount each time a user likes/dislikes that post. This way you won't actually have to search through the "Likes" collection over and over again everytime your have to show that data.

Related

Chat app lookup and write performance: additionan lookup for user with each message vs. bulk message edit on user info update?

I use MongoDB to store chat message documents in comments collection:
{
message: String,
id: String,
status: String,
author: {
id: String,
role: String,
title: String,
image: String,
},
... // plus some more stuff
}
Full user credentials are stored in users collection:
{
id: String,
title: String,
image: String,
text: String,
role: { type: String, default: "member" },
suspend: Boolean
}
Using this architecture, I can display a user profile icon, their full name, their badge (user role, such as "admin"), and a link to their full profile.
This architecture lets me create a single lookup to create a chat message. If I have 100 messages, I'll query MongoDB for 100 messages, and we're done.
However, if the user wants to update their profile details, I would need to find all the messages they've ever created and change them in addition to their profile data in users collection.
It's possible that a single user can author thousands of messages.
Should I rewrite this so that fetching a message will also fetch user data afresh?
This way, to display a message, I'd have to look up a document in the comments and then use comments[comment].id to find the user.

Duplicate key error while using _id from another collection

I have 2 collections so far.
The first is a 'Users' collection (That works well), and the other is a 'Rooms' collection (both created for a chat application).
I want every room to have a "users" array that will contain the user._id of every user that is in that room,
meaning I should be able to put the same user._id (from the user collection) in every one of the rooms right?
After creating a room successfully with 2 user._ids in the "users" array,
I tried making another one using one of the user._ids I used in the first room.
Then I got this error:
MongoError: E11000 duplicate key error collection: ratchat.rooms index: users_1 dup key:
{ users: "5fe08d452f34530e641d8f8c" }
After checking with a debugger I've found that the error occurs only when I use a user._id that is already used in another room's "users" array.
The only thing I could think of that could cause this problem is the Room schema,
maybe there's something I missed while reading the docs...
At first my Room schema looked like this:
const roomSchema = new mongoose.Schema({
users: [String],
hasLeft: [String],
isGroup: { type: Boolean, default: false },
},
});
const Room = mongoose.model("Room", roomSchema);
Then I thought maybe mongoDB needs to know that the ObjectIds that are in the users array are just references to another collection:
const roomSchema = new mongoose.Schema({
users: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
hasLeft: [String],
isGroup: { type: Boolean, default: false },
},
});
const Room = mongoose.model("Room", roomSchema);
No luck so far...
{autoIndex: false}
After research, I have found the reason for this error:
mongoose automatically creates indexes,
this is not only a duplicate error issue, but can cause a significant performance impact later in production.
According to mongoose docs, you can easily disable this behavior by setting the autoIndex option of your schema to false, or globally on the connection by setting the option autoIndex to false.
mongoose.connect('mongodb://user:pass#localhost:port/database', { autoIndex: false });
// or
mongoose.createConnection('mongodb://user:pass#localhost:port/database', { autoIndex: false });
// or
animalSchema.set('autoIndex', false);
// or
new Schema({..}, { autoIndex: false });
Don't forget to drop the entire collection before trying again
Because the collection is already indexed, emptying it completely won't work.
You have to drop the entire collection.

MongoDB RESTful API structuring

So, I'm trying to create a RESTful API that works similar to reddit, where it has users, topics(subreddits), posts and comments. For that I'm trying to use Node.js and MongoDB.
This is the github repo so far: https://github.com/edmassarani/reddit-clone
The only problem is I don't know how to structure the deletion of documents and it's "dependencies" because a user might own a topic, that topic has posts, those posts have comments and those comments have authors, so how would I go about deleting a user without leaving behind a topic with no owner or a post with no topic and so on? Would it be easier if I were to use a relational database?
I can see on your Github repo that your structured your models like in a relational database (note : you named relational db as 'SQL database' on your question) with normalized data models :
Example :
In Topic.js, you refer Posts with reference :
posts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post',
},
],
It certainly works like it, but with NoSQL and specially with MongoDB you have possibility to embed documents into another document.
Why do not embed Post schema directly into Topic like it :
posts: [
{
title: {
type: String,
required: true,
},
body: {
type: String,
required: true,
},
...
upvotes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
],
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment',
},
],
},
],
As I can understand, if a Topic is deleted, all Posts related to this Topic have to be deleted.
With embedded schema, you have only one deletion to do.
I don't know if in your context embedded is the best solution (because of perfs), but you have two solutions :
Use different schema (your models files) and you have to manually
delete in cascade (exemple : when you delete a Topic, you have to
find all Posts references into the Topic and delete them...)
Refactoring and embed : with it, deleting the Topic is also deleting Comments.
See mongodb official docs for more information on embedded schema : https://docs.mongodb.com/manual/core/data-model-design/

Ratings not updating as expected in Mongo

I'm trying to implement a rating system along the lines of upvotes/downvotes.
Users can vote on a lesson only once. They can switch their votes between up and down. Voting the same as their previous vote removes their vote.
I'm trying to accomplish this with pull() but it empties out the entire ratings array including other users' votes.
Rating Schema
var RatingSchema = new Schema({
rating: Boolean,
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
Lesson Schema
var LessonSchema = new Schema({
...,
ratings: [RatingSchema]
});
Problem code
//assuming lesson.ratings looks like this
[{user: 123..., rating: true},
{user: 321..., rating: true}];
//assuming lesson was loaded from a query
lesson.ratings.pull({user: 123...});
//resulting ratings
[]
I don't if this is expected behavior but I just want to remove the matching rating and not all of the sub docs.
Found a working sol'n.
The problem was the way the rating schema was originally defined and how save() works:
OG Rating Schema
var Ratings = new Schema({
_id: false,
rating: Boolean,
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
I thought the user ref would be unique enough to work with wrt modifying ratings.
I still don't know why the pull() would delete all subdocs regardless of user id.
When its time to save, because of the lack of _id, it updated the entire ratings array overwriting altogether.
To fix this instead of using the user to update, I switched it to use _id.
Also, careful when switching the _id flag on and off again. The driver will throw undefined objectid errs.

Using mongojs and node.js, how to find documents using multiple attributes as criteria

I am trying to use the find method to return documents that meet multiple criteria like so:
db.issues.find({ 'title.name': name, 'title.year': year, 'title.publisher': publisher }, function(err, issues) { ...
I get an empty array back as a result.
If I try the same query directly in the mongodb console, I get the results back as expected.
In mongojs, I am able to retrieve results if I only supply one attribute, like so:
db.issues.find({ 'title.name': name }, function(err, issues) { ...
So, how do I perform a search using multiple attributes? Do I need to use a different method?
UPDATED 2/2/2014 7:56
The issue schema is as follows:
{
title: { name: 'Some title name', year: 1999, publisher: 'Some publisher' },
number: "122",
variant: null,
print: "1",
year: "1999",
certification: { type: "Some certification", grade: 10 },
url: "http://www.someurl.com",
sales: []
}
There is no difference in how mongojs handles queries as it's intention is to mimic ( somewhat ) the behavior of the mongo shell.
Are you sure your criteria actually returns something? As it stands you possibly have an issue there. If you still cannot diagnose this, post up the result you expect to get and some of your schema as an edit. Don't forget to check your var's that numbers aren't strings and vice versa.

Categories