Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update preference job to handle compound unique key with group_id #4078

Merged
merged 3 commits into from
Dec 14, 2024

Conversation

Baalmart
Copy link
Contributor

@Baalmart Baalmart commented Dec 14, 2024

Description

Recent changes to the user preference schema introduced a compound unique index using user_id and group_id. The existing preference update job was failing for new users due to duplicate key errors when attempting to create or update preferences.

The original implementation did not account for the new unique key constraint, which requires both user_id and group_id to be unique together. This led to MongoDB duplicate key errors when trying to create or update preferences for users.

  • Refactored the preference update job to explicitly handle the new unique key constraint

  • Added explicit group_id filtering and assignment during preference updates

  • Implemented robust upsert logic to handle preference creation and updates

  • Maintained existing business logic for default preference generation

  • Improved error handling and logging for preference update processes

  • Modified updatePreferences function to use a specific group_id

  • Added upsert and setDefaultsOnInsert options to handle document creation

  • Ensured consistency in preference creation across different user batches

  • Preserved existing default preference generation logic

Changes Made

  • Modified updatePreferences function to explicitly handle group_id in preference queries
  • Added defaultGroupId to ensure consistent group assignment during preference updates
  • Updated preference creation and update logic to use compound user_id and group_id unique key
  • Implemented upsert and setDefaultsOnInsert options to handle edge cases in preference document creation
  • Refined querying logic to filter preferences by both user_id and group_id
  • Enhanced error logging for preference update failures
  • Ensured default preference object includes the specific group_id

Testing

  • Tested locally
  • Tested against staging environment
  • Relevant tests passed: [List test names]

Affected Services

  • Which services were modified:
    • Auth Service

API Documentation Updated?

  • Yes, API documentation was updated
  • No, API documentation does not need updating

Additional Notes

This modification should resolve the duplicate key error by explicitly specifying the group_id in both the query and the document creation/update process. The job will now create or update preferences with the specific group ID, avoiding duplicate key conflicts.

Summary by CodeRabbit

  • New Features

    • Enhanced user preferences update logic to include group-specific filtering.
    • Introduced a default group identifier for preference operations.
    • Added validation for critical default values and user group membership.
  • Bug Fixes

    • Improved error handling during preference creation and updates.

Copy link

codecov bot commented Dec 14, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 11.81%. Comparing base (78bbc1a) to head (8d97388).
Report is 13 commits behind head on staging.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           staging    #4078   +/-   ##
========================================
  Coverage    11.81%   11.81%           
========================================
  Files          115      115           
  Lines        15482    15482           
  Branches       319      319           
========================================
  Hits          1829     1829           
  Misses       13653    13653           

Copy link
Contributor

Auth-service changes in this PR available for preview here

Copy link
Contributor

coderabbitai bot commented Dec 14, 2024

Warning

Rate limit exceeded

@Baalmart has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 6 minutes and 53 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 7170b4a and 8d97388.

📒 Files selected for processing (1)
  • src/auth-service/bin/jobs/preferences-update-job.js (7 hunks)
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request modifies the preferences-update-job.js file to enhance user preference management by introducing a defaultGroupId and refining the preference update logic. The changes focus on incorporating a specific group identifier into preference queries and updates, utilizing Mongoose's ObjectId for more precise MongoDB operations. The modifications ensure more robust preference handling by explicitly including the group ID in fetching, creating, and updating preference records.

Changes

File Change Summary
src/auth-service/bin/jobs/preferences-update-job.js - Added defaultGroupId using Mongoose ObjectId
- Updated updatePreferences function to include group_id in queries
- Modified preference fetching and creation logic to use group_id
- Enhanced findOneAndUpdate with upsert and setDefaultsOnInsert options
- Introduced validateDefaultValues and validateUserGroupMembership functions for validation

Possibly related PRs

Suggested Reviewers

  • OchiengPaul442
  • Codebmk

Poem

🔧 Preferences dance, a MongoDB ballet,
Group IDs whisper, finding their way
Mongoose guides with ObjectId's might
Updating records, making logic tight
A code symphony of data's delight! 🎉


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
src/auth-service/bin/jobs/preferences-update-job.js (1)

124-124: Handle errors during preference creation more robustly

Currently, errors during the creation of preferences are logged but not handled further. Consider implementing additional error handling, such as retries or notifications, to ensure that critical operations are not silently failing.

You might refactor the error handling like this:

await PreferenceModel("airqo")
  .create(defaultPreferenceWithGroupId)
  .catch((error) => {
    logger.error(
      `🐛🐛 Failed to create preference for user ${userIdStr}: ${stringify(
        error
      )}`
    );
+   // Additional error handling logic here
  });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a63d39 and 86d0349.

📒 Files selected for processing (1)
  • src/auth-service/bin/jobs/preferences-update-job.js (5 hunks)
🔇 Additional comments (3)
src/auth-service/bin/jobs/preferences-update-job.js (3)

145-146: Confirm that defaults are set in your Mongoose schema

Using setDefaultsOnInsert: true with upsert: true ensures defaults are applied when a new document is inserted. Verify that your PreferenceModel schema has default values defined for the necessary fields.


3-3: Ensure mongoose is included in your dependencies

The import statement for mongoose has been added. Please verify that mongoose is listed as a dependency in your package.json to prevent any runtime issues.

Run the following script to check if mongoose is declared in your package.json dependencies:

✅ Verification successful

mongoose dependency is properly configured

The mongoose package is already included in the auth-service dependencies with version ^5.12.14, so no additional action is required.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that mongoose is listed as a dependency in package.json

cat package.json | jq '.dependencies.mongoose'

Length of output: 91


Script:

#!/bin/bash
# Let's first find the package.json files in the repository
fd package.json

# Then let's check for mongoose in all package.json files
fd package.json --exec cat {} \; | grep -i mongoose

Length of output: 816


Script:

#!/bin/bash
# Let's specifically check the auth-service package.json since that's where our file is located
cat src/auth-service/package.json | jq '.dependencies.mongoose'

Length of output: 74


97-99: Confirm the data type consistency of group_id in the query

When querying the PreferenceModel, ensure that the group_id field's data type in the query matches the type stored in the database. If group_id is stored as a string in the database, you might need to adjust the query accordingly.

Run the following script to verify the data type of group_id in your database:

✅ Verification successful

Let me analyze the schema definitions to determine the data type of group_id. Since we don't have direct database access, examining the model definitions will help us understand the expected data type.


I need to check the specific schema definition for the Preference model to verify the data type of group_id field.


Data type consistency for group_id is correctly implemented

The schema definition shows that group_id is properly defined as ObjectId type and references the "group" collection:

group_id: {
  type: ObjectId,
  ref: "group",
  default: mongoose.Types.ObjectId(constants.DEFAULT_GROUP),
}

The query in the code is using defaultGroupId which would be an ObjectId, making it consistent with the schema definition. The data type matches the model's expectations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the data type of 'group_id' in the 'preferences' collection

# Replace 'yourDatabase' and 'preferences' with the actual database and collection names
mongo yourDatabase --eval 'db.preferences.findOne({}, {group_id: 1})'

# Expected outcome: The output shows the data type of 'group_id'

Length of output: 167


Script:

#!/bin/bash
# Let's check the schema definition and model files to understand the data type
# First, let's find relevant model files
fd -t f "preference" -X grep -l "group_id"

# Then, let's examine the schema definition
ast-grep --pattern 'group_id: {
  $$$
}'

# Also search for mongoose schema definitions
rg -A 5 "new (mongoose\.Schema|Schema)\(" 

Length of output: 65688


Script:

#!/bin/bash
# Let's examine the Preference model definition specifically
cat ./src/auth-service/models/Preference.js

Length of output: 16233

Comment on lines +114 to +119
const defaultPreferenceWithGroupId = {
...defaultPreference,
user_id: user._id,
group_id: defaultGroupId,
selected_sites: selectedSites,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure all required fields are included in defaultPreferenceWithGroupId

While constructing defaultPreferenceWithGroupId, make sure that all required fields defined in the PreferenceModel schema are included. This prevents validation errors during creation or update operations.

Review the PreferenceModel schema and update defaultPreferenceWithGroupId if any required fields are missing.

Comment on lines 79 to 80
const defaultGroupId = mongoose.Types.ObjectId("64f54e4621d9b90013925a08");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid hardcoding the defaultGroupId

Hardcoding the group_id can lead to maintenance challenges and reduced flexibility across different environments. Consider retrieving the defaultGroupId from a configuration file or environment variable to enhance configurability.

Apply this diff to refactor:

-const defaultGroupId = mongoose.Types.ObjectId("64f54e4621d9b90013925a08");
+const defaultGroupId = mongoose.Types.ObjectId(process.env.DEFAULT_GROUP_ID);

Ensure that DEFAULT_GROUP_ID is defined in your environment variables for all deployment environments.

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
src/auth-service/bin/jobs/preferences-update-job.js (1)

114-119: Avoid potential duplication of 'group_id' in preference objects

Since defaultPreference already includes a group_id, adding it again may cause confusion. Consider removing group_id from defaultPreference or ensure that it is intentionally overwritten.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a63d39 and 86d0349.

📒 Files selected for processing (1)
  • src/auth-service/bin/jobs/preferences-update-job.js (5 hunks)
🔇 Additional comments (5)
src/auth-service/bin/jobs/preferences-update-job.js (5)

3-3: Importing 'mongoose' for ObjectId usage

Including mongoose here is appropriate for utilizing Types.ObjectId in your code.


96-99: Including 'group_id' in the query ensures accurate preference retrieval

Adding group_id to the query correctly handles the compound unique key, ensuring that preferences are fetched accurately.


145-146: Verify the necessity of 'setDefaultsOnInsert' option

When using $set with explicit values, setDefaultsOnInsert may not apply schema defaults as intended. Verify if this option is needed, as the provided values might override the defaults.

Consider reviewing Mongoose's documentation on the behavior of setDefaultsOnInsert when using $set.


124-124: Creating new preferences with comprehensive data

Using .create with defaultPreferenceWithGroupId ensures that new preferences are initialized with all required fields, including group_id.


137-138: Including 'group_id' in the update criteria ensures correct targeting

Adding group_id to the findOneAndUpdate query criteria ensures that the update targets the correct preference document, which is essential with the compound unique key.

Comment on lines 141 to 142
$set: defaultPreferenceWithGroupId,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prevent overwriting existing preference data

Using $set: defaultPreferenceWithGroupId might unintentionally overwrite existing preference fields. To avoid data loss, update only the necessary fields.

Modify the update operation to set specific fields:

-$set: defaultPreferenceWithGroupId,
+$set: {
+  selected_sites: selectedSites,
+  group_id: defaultGroupId,
+},

This approach updates only the selected_sites and group_id fields, preserving other preference data.

Committable suggestion skipped: line range outside the PR's diff.

@@ -74,6 +75,9 @@
return;
}

// Specify the group_id you want to use
const defaultGroupId = mongoose.Types.ObjectId("64f54e4621d9b90013925a08");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid hardcoding the 'defaultGroupId' value

Consider moving the defaultGroupId to a configuration file or an environment variable. Hardcoding ObjectIds can make future maintenance challenging if the ID changes.

Apply this change to use a constant or environment variable:

-const defaultGroupId = mongoose.Types.ObjectId("64f54e4621d9b90013925a08");
+const defaultGroupId = mongoose.Types.ObjectId(process.env.DEFAULT_GROUP_ID || constants.DEFAULT_GROUP_ID);

Ensure that process.env.DEFAULT_GROUP_ID or constants.DEFAULT_GROUP_ID provides the correct ObjectId value.

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
src/auth-service/bin/jobs/preferences-update-job.js (2)

61-70: Consider adding type checking for defaultGroupId parameter.

While the function is well-implemented, it might be good to add a type check for the defaultGroupId parameter to ensure it's a valid ObjectId.

 const validateUserGroupMembership = (user, defaultGroupId) => {
+  if (!mongoose.Types.ObjectId.isValid(defaultGroupId)) {
+    return false;
+  }
   if (!user.group_roles || user.group_roles.length === 0) {
     return false;
   }
   return user.group_roles.some(
     (role) => role.group.toString() === defaultGroupId.toString()
   );
 };

119-120: Consider adding error handling for ObjectId conversion.

While the code works, it might be good to add try-catch for the ObjectId conversion as it could throw an error if the constant value is invalid.

-    const defaultGroupId = mongoose.Types.ObjectId(constants.DEFAULT_GROUP);
+    let defaultGroupId;
+    try {
+      defaultGroupId = mongoose.Types.ObjectId(constants.DEFAULT_GROUP);
+    } catch (error) {
+      logger.error(`Invalid DEFAULT_GROUP value: ${constants.DEFAULT_GROUP}`);
+      return;
+    }

Also applies to: 135-138

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 86d0349 and 7170b4a.

📒 Files selected for processing (1)
  • src/auth-service/bin/jobs/preferences-update-job.js (7 hunks)
🔇 Additional comments (6)
src/auth-service/bin/jobs/preferences-update-job.js (6)

3-3: LGTM! Good practice using constants for default values.

The mongoose import and direct use of constants in defaultPreference improve code maintainability and consistency.

Also applies to: 55-58


16-38: Well-structured validation function with clear error handling.

The validateDefaultValues function provides a robust check for critical configuration values. The error message clearly identifies missing values, making troubleshooting easier.


102-105: Good practice implementing early validation.

Early validation check prevents unnecessary processing and database operations if critical values are missing.


143-148: Well-implemented compound query for preferences.

The query correctly uses both user_id and group_id, aligning with the compound unique key requirement.


161-167: Well-structured update logic with proper MongoDB options.

The update logic correctly handles the compound unique key and uses appropriate MongoDB options for atomic operations. The use of setDefaultsOnInsert is particularly good for maintaining data consistency.

Also applies to: 185-195


220-221: Clean module exports.

Good practice exporting the updatePreferences function, making it available for testing and reuse.

Copy link
Contributor

Auth-service changes in this PR available for preview here

Copy link
Contributor

Auth-service changes in this PR available for preview here

@Baalmart Baalmart merged commit 331742e into staging Dec 14, 2024
52 checks passed
@Baalmart Baalmart deleted the hf-preferences-updates-1 branch December 14, 2024 09:17
@Baalmart Baalmart mentioned this pull request Dec 14, 2024
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant