-
Notifications
You must be signed in to change notification settings - Fork 3
Tag update #326
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
base: main
Are you sure you want to change the base?
Tag update #326
Changes from all commits
b3a76ca
a28c2ca
ac262e5
e22e4e4
f83ea3c
791ae67
8e22c82
d972adf
60efd6f
c28a60d
33e9adb
1c544b7
14b5c5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import * as dotenv from 'dotenv'; | ||
|
|
||
| dotenv.config(); | ||
|
|
||
| import { Collection, Db, MongoClient } from 'mongodb'; | ||
|
|
||
| const { MONGO_URL = 'mongodb://localhost:27017/erxes?directConnection=true' } = | ||
| process.env; | ||
|
|
||
| if (!MONGO_URL) { | ||
| throw new Error(`Environment variable MONGO_URL not set.`); | ||
| } | ||
|
|
||
| const client = new MongoClient(MONGO_URL); | ||
|
|
||
| let db: Db; | ||
| let Tags: Collection; | ||
|
|
||
| const command = async () => { | ||
| await client.connect(); | ||
| db = client.db() as Db; | ||
|
|
||
| Tags = db.collection('tags'); | ||
|
|
||
| try { | ||
| await Tags.updateMany( | ||
| {}, | ||
| { | ||
| $unset: { scopeBrandIds: '' }, | ||
| $set: { isGroup: false, parentId: '', order: '' }, // flatten parentId: no nested parent tags allowed | ||
| }, | ||
| ); | ||
| } catch (e) { | ||
| console.log(`Error occurred: ${e.message}`); | ||
| await client.close(); | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure client connection is closed on success too (e.g., in a finally block) to avoid leaving open connections. |
||
| console.log(`Process finished at: ${new Date().toISOString()}`); | ||
|
|
||
| await client.close(); | ||
| process.exit(); | ||
| }; | ||
|
|
||
| command(); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -223,5 +223,31 @@ export const customerRouter = t.router({ | |
| data: doc, | ||
| }); | ||
| }), | ||
|
|
||
| tag: t.procedure.input(z.any()).mutation(async ({ ctx, input }) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using z.any() for input and remove debug console.log; add stricter validation and remove logging of raw inputs in production. |
||
| const { action, _ids, tagIds, targetIds } = input; | ||
| const { models } = ctx; | ||
|
|
||
| let response = {}; | ||
|
|
||
| if (action === 'count') { | ||
| response = await models.Customers.countDocuments({ | ||
| tagIds: { $in: _ids }, | ||
| }); | ||
| } | ||
|
|
||
| if (action === 'tagObject') { | ||
| await models.Customers.updateMany( | ||
| { _id: { $in: targetIds } }, | ||
| { $set: { tagIds } }, | ||
| ); | ||
|
|
||
| response = await models.Customers.find({ | ||
| _id: { $in: targetIds }, | ||
| }).lean(); | ||
| } | ||
|
|
||
| return response; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider handling unexpected 'action' values in the 'tag' procedure (e.g. add a default case or error throw) to avoid returning an empty response. |
||
| }), | ||
| }), | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ export const documentSchema = new Schema( | |
| name: { type: String }, | ||
| content: { type: String }, | ||
| replacer: { type: String }, | ||
| code: { type: String }, | ||
| code: { type: String, optional: true }, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainUnique index on an optional field will cause duplicate-key errors; use a partial index and drop "optional".
Apply: - code: { type: String, optional: true },
+ code: { type: String, required: false, trim: true },
-documentSchema.index({ code: 1 }, { unique: true });
+documentSchema.index(
+ { code: 1 },
+ { unique: true, partialFilterExpression: { code: { $exists: true } } }
+);Verification (run in mongosh against the target DB): Also applies to: 18-18 🏁 Script executed: db.getCollection('documents').getIndexes()
# Expect the 'code_1' index to have { unique: true, partialFilterExpression: { code: { $exists: true } } }Length of output: 235 🏁 Script executed: #!/bin/bash
# Print the 'code' field definition and surrounding lines
rg -n "code:\s*\{" -C2 backend/core-api/src/modules/documents/db/definitions/documents.ts
# Print all index definitions on documentSchema
rg -n "documentSchema\.index" -C3 backend/core-api/src/modules/documents/db/definitions/documents.tsLength of output: 398 Use required:false (not optional) and add a partial filter to the unique ‘code’ index Replace the field and index definitions as follows: - code: { type: String, optional: true },
+ code: { type: String, required: false, trim: true },
- documentSchema.index({ code: 1 }, { unique: true });
+ documentSchema.index(
+ { code: 1 },
+ { unique: true, partialFilterExpression: { code: { $exists: true } } }
+ );After deployment, in the Mongo shell run: db.getCollection('documents').getIndexes();and confirm that the 🤖 Prompt for AI Agents |
||
| }, | ||
| { | ||
| timestamps: true, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,32 +5,20 @@ export const tagSchema = schemaWrapper( | |
| new Schema( | ||
| { | ||
| _id: mongooseStringRandomId, | ||
| name: { type: String, label: 'Name' }, | ||
| type: { | ||
| type: String, | ||
| label: 'Type', | ||
| index: true, | ||
| }, | ||
| name: { type: String, label: 'Name', unique: true }, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainGlobal unique on name is risky; scope uniqueness. unique: true enforces cross-tenant/global uniqueness and blocks same-name tags under different groups. Prefer a compound unique index (name, parentId) or include tenant scope (e.g., organizationId). - name: { type: String, label: 'Name', unique: true },
+ name: { type: String, label: 'Name' },
@@
-tagSchema.index({ _id: 1, name: 1, parentId: 1 });
+tagSchema.index({ _id: 1, name: 1, parentId: 1 });
+// Enforce uniqueness only within the same parent (adjust to include tenant scope if applicable)
+tagSchema.index({ name: 1, parentId: 1 }, { unique: true });If a unique index on name already exists in prod, we’ll need a migration to drop it before adding the compound index. I can prepare it. 🏁 Script executed: #!/bin/bash
# Locate the tags.ts schema definition
fd -t f tags.ts
# Preview the top of the file to see field definitions
sed -n '1,200p' backend/core-api/src/modules/tags/db/definitions/tags.ts
# Inspect the schema object and index declarations
rg -n "tagSchema" -C3 backend/core-api/src/modules/tags/db/definitions/tags.ts
rg -n "index" -C3 backend/core-api/src/modules/tags/db/definitions/tags.ts
# Check for tenant or hierarchical scope fields
rg -n "parentId" -C3 backend/core-api/src/modules/tags/db/definitions/tags.ts
rg -n "organizationId" -C3 backend/core-api/src/modules/tags/db/definitions/tags.tsLength of output: 2612 Scope tag name uniqueness to its parent (and tenant)
|
||
| colorCode: { type: String, label: 'Color code' }, | ||
| parentId: { type: String, label: 'Parent' }, | ||
| relatedIds: { type: [String], label: 'Children tag ids' }, | ||
| isGroup: { type: Boolean, label: 'Is group', default: false }, | ||
| type: { type: String, label: 'Content type' }, | ||
| description: { type: String, label: 'Description' }, | ||
| objectCount: { type: Number, label: 'Object count' }, | ||
| order: { type: String, label: 'Order', index: true }, | ||
| parentId: { | ||
| type: String, | ||
| optional: true, | ||
| index: true, | ||
| label: 'Parent', | ||
| }, | ||
| relatedIds: { | ||
| type: [String], | ||
| optional: true, | ||
| label: 'Children tag ids', | ||
| }, | ||
| order: { type: String, label: 'Order' }, | ||
| }, | ||
| { | ||
| timestamps: true, | ||
| }, | ||
| ), | ||
| ); | ||
|
|
||
| // for tags query. increases search speed, avoids in-memory sorting | ||
| tagSchema.index({ _id: 1, type: 1, order: 1, name: 1, createdAt: 1 }); | ||
| tagSchema.index({ _id: 1, name: 1, parentId: 1, type: 1 }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call client.close() before process.exit() for proper cleanup of the MongoDB connection.