実現したいこと
ある会社では従業員情報を下記のようなNoSQLのドキュメント指向データベースに保存している。
従業員情報は、従業員自身が社内ポータルサイトで検索・閲覧することができる。
社内ポータルサイトは、ログインID/PWの他に、部署名と役職名も入力した上でログインする必要がある。
公開範囲・・・ログイン者に応じて表示するかしないかを設定したもの。
例えば、西村の場合、ログイン者が営業部または技術部の課長以上のみに表示するように公開範囲を設定しています(ログイン者がリーダーだったり、人事部だったりした場合は表示しない)
※{}の場合は全員に公開の意味です。
例)公開範囲=役職:{}、部署:技術部だったら、技術部の人には誰でも公開し、技術部以外の人だったら非公開にします。
JSON
1{ 2 //-------------------- 3 //従業員コレクション 4 //-------------------- 5 "従業員": { 6 //-------------------- 7 //各ドキュメント 8 //-------------------- 9 "西村": { 10 //-------------------- 11 //各データ 12 //-------------------- 13 "年齢": 25, 14 "月給": "30万円", 15 "婚姻歴": "あり", 16 "部署": "技術部", 17 "役職": "平社員", 18 "公開範囲": { 19 "役職": "課長以上", 20 "部署": "営業部,技術部" 21 } 22 }, 23 "田中": { 24 "年齢": 40, 25 "月給": "35万円", 26 "婚姻歴": "なし", 27 "部署": "技術部", 28 "役職": "平社員", 29 "公開範囲": {} 30 }, 31 "秋山": { 32 "年齢": 31, 33 "月給": "60万円", 34 "婚姻歴": "なし", 35 "部署": "人事部", 36 "役職": "平社員", 37 "公開範囲": { 38 "役職": {}, 39 "部署": "技術部" 40 } 41 }, 42 "小田": { 43 "年齢": 45, 44 "月給": "70万円", 45 "婚姻歴": "あり", 46 "部署": "営業部", 47 "役職": "リーダー", 48 "公開範囲": { 49 "役職": "リーダー以上", 50 "部署": "人事部" 51 } 52 }, 53 "木村": { 54 "年齢": 33, 55 "月給": "83万円", 56 "婚姻歴": "あり", 57 "部署": "技術部", 58 "役職": "課長", 59 "公開範囲": { 60 "役職": "課長以上", 61 "部署": {} 62 } 63 }, 64 "岡部": { 65 "年齢": 56, 66 "月給": "130万円", 67 "婚姻歴": "なし", 68 "部署": "秘書室", 69 "役職": "部長", 70 "公開範囲": { 71 "役職": "課長以上", 72 "部署": "営業部,技術部,人事部" 73 } 74 } 75 } 76}
発生している問題・分からないこと
質問
こんなDB検索を実現する際、どのようにプログラムを組めばいいでしょうか?
例えば、秋山がログインしました。
ポータルサイト側の検索項目に「部署:技術部」で検索条件を掛けたとします。
その場合、「西村、田中、木村」がヒットしますが、秋山は人事部の平社員です。
なので、西村と木村はヒットされず、「田中のみ」を表示したいです。
例えば、岡部がログインしました。
ポータルサイト側の検索項目に「全社員を対象」で検索条件を掛けたとします。
その場合、「西村、田中、秋山、小田、木村、岡部」がヒットしますが、岡部は秘書室の部長です。
なので、「田中、木村」を表示したいです。
該当のソースコード
特になし
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
Google検索をしてみましたが、こういう構成のシステムでNoSQLを使った記事を見つける事が出来なかったので質問させて頂きました。
Firebaseからの単純なGetは以下のようになることは理解しています。
Dart
1final userDoc = await FirebaseFirestore 2 .instance 3 .collection('従業員') 4 .doc('西村') 5 .get();
Where句を使うパターンも下記記事で学習しました。
- https://zenn.dev/joo_hashi/articles/13fd1d2e2d3397
- https://firebase.google.com/docs/firestore/query-data/queries?hl=ja
ただ、質問のようなものは結構複雑になるのでどう実現したらいいかまだ想像着かないのが現状です。
私が考えた案は、一旦ポータルサイト側の検索条件にヒットする全員をGetした上で、Dart関数内でループ処理させ、(ざっくりですみません→)「if ( userDoc[i].公開範囲.役職 == xxxxx ) 」みたいな感じで回していくのが早そうではありましたが、従業員数の増加に応じて処理が重くなる懸念もありそうだと感じました。
DB側で検索できたらいいなと思った次第です。
また、もし「このシステムの構成だったらAWSやNoSQL以外の方がいい」などあればご教授いただければ幸いです。
補足
特になし
その後追記(参考までにChatGPTに質問した結果を追記)
試しに、ChatGPT o4-mini(プログラミング領域特化モデル)に尋ねて見たところこのような結果が出力されました。
プロンプト
ある会社では従業員情報を下記のようなNoSQLのドキュメント指向データベースに保存している。 従業員情報は、従業員自身が社内ポータルサイトで検索・閲覧することができる。 社内ポータルサイトは、ログインID/PWの他に、部署名と役職名も入力した上でログインする必要がある。 公開範囲・・・ログイン者に応じて表示するかしないかを設定したもの。 例えば、西村の場合、ログイン者が営業部または技術部の課長以上のみに表示するように公開範囲を設定しています(ログイン者がリーダーだったり、人事部だったりした場合は表示しない) ※{}の場合は全員に公開の意味です。 例)公開範囲=役職:{}、部署:技術部だったら、技術部の人には誰でも公開し、技術部以外の人だったら非公開にします。 以下のJSONはNoSQLの構造です。 { "従業員": { "西村": { "年齢": 25, "月給": "30万円", "婚姻歴": "あり", "部署": "技術部", "役職": "平社員", "公開範囲": { "役職": "課長以上", "部署": "営業部,技術部" } }, "田中": { "年齢": 40, "月給": "35万円", "婚姻歴": "なし", "部署": "技術部", "役職": "平社員", "公開範囲": {} }, "秋山": { "年齢": 31, "月給": "60万円", "婚姻歴": "なし", "部署": "人事部", "役職": "平社員", "公開範囲": { "役職": {}, "部署": "技術部" } }, "小田": { "年齢": 45, "月給": "70万円", "婚姻歴": "あり", "部署": "営業部", "役職": "リーダー", "公開範囲": { "役職": "リーダー以上", "部署": "人事部" } }, "木村": { "年齢": 33, "月給": "83万円", "婚姻歴": "あり", "部署": "技術部", "役職": "課長", "公開範囲": { "役職": "課長以上", "部署": {} } }, "岡部": { "年齢": 56, "月給": "130万円", "婚姻歴": "なし", "部署": "秘書室", "役職": "部長", "公開範囲": { "役職": "課長以上", "部署": "営業部,技術部,人事部" } } } } こんなDB検索を実現する際、どのようにDartプログラムを組めばいいでしょうか? 例1)秋山がログインしました。ポータルサイト側の検索項目に「部署:技術部」で検索条件を掛けたとします。 その場合、「西村、田中、木村」がヒットしますが、秋山は人事部の平社員です。なので、西村と木村はヒットされず、「田中のみ」を表示したいです。 例2)岡部がログインしました。 ポータルサイト側の検索項目に「全社員を対象」で検索条件を掛けたとします。 その場合、「西村、田中、秋山、小田、木村、岡部」がヒットしますが、岡部は秘書室の部長です。 なので、「田中、木村」を表示したいです。 一般的なソースコードは「final userDoc = await FirebaseFirestore.instance.collection('従業員').doc('西村') .get();」になると思います。上記の「例1,例2」を実現するためのプログラムを作成してください。
出力結果
✅ 前提 Firestore コレクション名: 従業員 各ドキュメント名が従業員名(例: 西村, 田中) ログイン情報として 部署 と 役職 を使って可視性チェック 公開範囲に基づいて、表示対象を制限 ✅ Dartコード:アクセス制御付きの従業員検索 import 'package:cloud_firestore/cloud_firestore.dart'; Future<List<String>> fetchVisibleEmployees({ required String loginUserName, required String loginDepartment, required String loginPosition, String? searchDepartment, }) async { final employeeSnapshot = await FirebaseFirestore.instance.collection('従業員').get(); final allEmployees = employeeSnapshot.docs; // 役職の序列定義(昇順) const positionHierarchy = ['平社員', 'リーダー', '課長', '部長', '本部長', '役員']; int getRank(String? position) { return positionHierarchy.indexOf(position ?? ''); } List<String> visibleEmployees = []; for (var doc in allEmployees) { final data = doc.data(); final name = doc.id; // 自分自身は非表示(必要であれば除外) if (name == loginUserName) continue; // 検索フィルタ if (searchDepartment != null && data['部署'] != searchDepartment) continue; final visibility = data['公開範囲'] as Map<String, dynamic>? ?? {}; final allowedPositions = (visibility['役職'] as String?)?.split(',') ?? []; final allowedDepartments = (visibility['部署'] as String?)?.split(',') ?? []; // 公開条件チェック final isPublicToAll = visibility.isEmpty; final isPositionMatch = allowedPositions.isEmpty || getRank(loginPosition) >= getRank(allowedPositions.first); final isDepartmentMatch = allowedDepartments.isEmpty || allowedDepartments.contains(loginDepartment); if (isPublicToAll || (isPositionMatch && isDepartmentMatch)) { visibleEmployees.add(name); } } return visibleEmployees; } ✅ 使い方例 例1: 秋山(人事部・平社員)が「技術部」で検索 final result = await fetchVisibleEmployees( loginUserName: '秋山', loginDepartment: '人事部', loginPosition: '平社員', searchDepartment: '技術部', ); // → 出力: ['田中'] 例2: 岡部(秘書室・部長)が全社員検索 dart コピーする 編集する final result = await fetchVisibleEmployees( loginUserName: '岡部', loginDepartment: '秘書室', loginPosition: '部長', ); // → 出力: ['田中', '木村'] 🔍 解説 getRank() によって役職の序列比較を可能にしています。 公開範囲が {}(空)の場合は全員に公開。 "課長以上" や "リーダー以上" のような表現ではなく、明示的な役職名を , 区切りで定義している前提で設計しています。 より柔軟にするには "以上" ロジックに合わせて条件分岐を追加する必要があります(必要なら拡張可能です)。

バッドをするには、ログインかつ
こちらの条件を満たす必要があります。