Skip to content

Commit f520449

Browse files
authored
Add MongoDB playground for finding field usages (#1724)
A simple playground that lets us look up the usages of a given field accross all projects/databases
1 parent 5fa999b commit f520449

1 file changed

Lines changed: 116 additions & 0 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
2+
3+
function verifyDbExists(dbName) {
4+
var database = db.getSiblingDB("admin")
5+
.runCommand({ "listDatabases": 1 })
6+
.databases.find(database => database.name === dbName);
7+
if (!exists) {
8+
throw new Error(`The database "${dbName}" does not exist.`)
9+
}
10+
}
11+
12+
function findEntriesThatUseFieldInDb(fieldPath, dbName, skipVerify) {
13+
skipVerify || verifyDbExists(dbName);
14+
15+
var lexicon = db.getSiblingDB(dbName).getCollection('lexicon');
16+
let matches = [];
17+
if (lexicon) {
18+
var cursor = lexicon.find({[fieldPath]: {"$exists" : true}});
19+
while (cursor.hasNext()) {
20+
var entry = cursor.next();
21+
if (entryHasNonEmptyValueForField(entry, fieldPath)) {
22+
matches.push({db: dbName, entry});
23+
}
24+
}
25+
}
26+
return matches;
27+
}
28+
29+
function findEntriesThatUseFieldInAllDbs(fieldPath, threshold) {
30+
threshold = threshold || 300;
31+
db = db.getSiblingDB("admin");
32+
dbs = db.runCommand({ "listDatabases": 1 }).databases;
33+
var results = [];
34+
35+
for (var i in dbs) {
36+
var database = dbs[i];
37+
var entries = findEntriesThatUseFieldInDb(fieldPath, database.name, true);
38+
results.push(...entries);
39+
if (results.length >= threshold) {
40+
print(`Maxed out at threshold (${threshold}).`)
41+
break;
42+
}
43+
}
44+
return results;
45+
}
46+
47+
function entryHasNonEmptyValueForField(entry, fieldPath) {
48+
if (!entry) {
49+
return false;
50+
}
51+
52+
return navigatePath(entry, fieldPath)
53+
.filter(fieldHasNonEmptyValue).length > 0;
54+
}
55+
56+
function fieldHasNonEmptyValue(field) {
57+
if (!field) {
58+
return false;
59+
}
60+
61+
if (field.value && field.value.trim()) {
62+
return true;
63+
}
64+
65+
for (var inputSystem in field) {
66+
if (field[inputSystem].value && field[inputSystem].value.trim()) {
67+
return true;
68+
}
69+
}
70+
71+
return false;
72+
}
73+
74+
function navigatePath(entry, path) {
75+
if (!entry) {
76+
return [];
77+
}
78+
79+
var step = path.split('.')[0];
80+
var result = entry[step];
81+
if (!result) {
82+
return [];
83+
}
84+
85+
var restPath = path.substring(path.indexOf(".") + 1);
86+
var isLastStep = path === restPath;
87+
if (isLastStep) {
88+
return Array.isArray(result) ? result : [result];
89+
} else {
90+
return Array.isArray(result)
91+
? result.flatMap(value => navigatePath(value, restPath))
92+
: navigatePath(result, restPath);
93+
}
94+
}
95+
96+
function getProjectId(dbName, projects) {
97+
const projectCode = dbName.replace('sf_', '');
98+
var project = projects.findOne({'projectCode': {$eq: projectCode}});
99+
return `${projectCode}::${project._id.toString()}`;
100+
}
101+
102+
function findNonEmptyValuesForField(fieldPath, dbName) {
103+
var results = dbName
104+
? findEntriesThatUseFieldInDb(fieldPath, dbName)
105+
: findEntriesThatUseFieldInAllDbs(fieldPath);
106+
var projects = db.getSiblingDB('scriptureforge').getCollection('projects');
107+
return results.flatMap(result => navigatePath(result.entry, fieldPath)
108+
.filter(fieldHasNonEmptyValue)
109+
.map(field => ({
110+
project: getProjectId(result.db, projects),
111+
entryId: result.entry._id.toString(),
112+
value: field.value || field.values || field,
113+
})));
114+
}
115+
116+
findNonEmptyValuesForField("senses.senseImportResidue");

0 commit comments

Comments
 (0)