34
6

MongoDBでデータの検索について試してみました

Last updated at Posted at 2024-07-09

MongoDBをDocker上に構築してみる」で MongDBの環境を作成したので、データの検索について試してみたいと思います。

初期データ

上記で初期データとして投入したものでは少し物足りないので、初期データを下記のものに入れ替えました。自分がRDBの考え方になっているので、リレーション風のデータの形で、投入してみます。

init_db.js
db = db.getSiblingDB('db_employee_info');

db.employee.insertMany([
    {
        employeeID: 'emp001',
        divisionID: 'ka001',
        roleID: 'yaku001',
        employeeName: '田村',
        age: 30,
        salary: 400000,
        created_date: new Date(),
        updated_date: new Date()
    },
    {
        employeeID: 'emp002',
        divisionID: 'ka001',
        roleID: 'yaku002',
        employeeName: '山田',
        age: 31,
        salary: 350000,
        created_date: new Date(),
        updated_date: new Date()
    },
    {
        employeeID: 'emp003',
        divisionID: 'ka002',
        roleID: 'yaku003',
        employeeName: '中山',
        age: 37,
        salary: 300000,
        created_date: new Date(),
        updated_date: new Date()
    },
    {
        employeeID: 'emp004',
        divisionID: 'ka002',
        roleID: 'yaku004',
        employeeName: '佐藤',
        age: 23,
        salary: 250000,
        created_date: new Date(),
        updated_date: new Date()
    },
    {
        employeeID: 'emp005',
        divisionID: 'ka003',
        roleID: 'yaku002',
        employeeName: '佐々木',
        age: 33,
        salary: 350000,
        created_date: new Date(),
        updated_date: new Date()
    },
    {
        employeeID: 'emp006',
        divisionID: 'ka004',
        roleID: 'yaku002',
        employeeName: '吉田',
        age: 35,
        salary: 350000,
        created_date: new Date(),
        updated_date: new Date()
    }
]);

MongoDBが起動されたら、NoSQL Booster で確認したところ、初期データが登録されていることが確認できました。
nosqlbooster_2.png

データベース用語の違い

MongoDBはスキーマレスであれことから、データベースで使用される用語が違います。MongoDBとRBDの違いを記しておきます。

RDB MongoDB
テーブル コレクション
ドキュメント
フィールド
プライマリキー ObjectID
インデックス インデックス

検索

検索:説明
> db.collection.find(
  { <検索条件> },
  { key1: 0, key2: 1, ・・・}
)

最初の{ }は検索条件を指定します。検索条件はJSONのような形式で記述します。
その後に、指定したフィールドだけを取得します。
key: 0 フィールドを非表示にする
key: 1 フィールドを表示する

検索:サンプル
> db_employee_info> db.employee.find({age:31})
[
  {
    _id: ObjectId('668b87b9e98d52fe42f3f54f'),
    employeeID: 'emp002',
    divisionID: 'ka001',
    roleID: 'yaku002',
    employeeName: '山田',
    age: 31,
    salary: 350000,
    created_date: ISODate('2024-07-08T06:31:21.820Z'),
    updated_date: ISODate('2024-07-08T06:31:21.820Z')
  }
]

> db_employee_info> db.employee.find({age:31},{_id:0, age:0})
[
  {
    employeeID: 'emp002',
    divisionID: 'ka001',
    roleID: 'yaku002',
    employeeName: '山田',
    salary: 350000,
    created_date: ISODate('2024-07-08T06:31:21.820Z'),
    updated_date: ISODate('2024-07-08T06:31:21.820Z')
  }
]

> db_employee_info> db.employee.find({age:31},{employeeName:1})
[
  { 
    _id: ObjectId('668b87b9e98d52fe42f3f54f'),
    employeeName: '山田'
  }
]

『_id』は、データを登録したときに自動で付与される主キーになります。

配列データ

MongoDBでは、配列のデータを保持することができます。

データ投入
db.employee.insertOne({
        employeeID: 'emp008',
        divisionID: 'ka001',
        roleID: 'yaku004',
        employeeName: '大田',
        age: 36,
        salary: 320000,
        skill: [ { name: "Oracle", level: 3},{ name: "MySQL", level: 2},{ name: "Redis", level: 1},{ name: "MongoDB", level: 5}],
        created_date: new Date(),
        updated_date: new Date()
        })

nosqlbooster_3.png

配列データの検索
> db.employee.find({"skill.level":3},{_id:0})
[
  {
    employeeID: 'emp008',
    divisionID: 'ka001',
    roleID: 'yaku004',
    employeeName: '大田',
    age: 36,
    salary: 320000,
    skill: [
      { name: 'Oracle', level: 3 },
      { name: 'MySQL', level: 2 },
      { name: 'Redis', level: 1 },
      { name: 'MongoDB', level: 5 }
    ],
    created_date: ISODate('2024-07-08T09:09:51.607Z'),
    updated_date: ISODate('2024-07-08T09:09:51.607Z')
  }
]

配列の中のオブジェクトを検索条件に指定する場合は『"配列.オブジェクトのプロパティ名"』を指定します。この場合、""(ダブルコーテーション)で括る必要があります。上記では、"skill.level" としています。

検索条件(完全一致/部分一致/前方一致/後方一致)

検索条件:完全一致
> db_employee_info> db.employee.find( { employeeName: '山田' },{ _id:0 } )
[
  {
    employeeID: 'emp002',
    divisionID: 'ka001',
    roleID: 'yaku002',
    employeeName: '山田',
    age: 31,
    salary: 350000,
    created_date: ISODate('2024-07-08T06:31:21.820Z'),
    updated_date: ISODate('2024-07-08T06:31:21.820Z')
  }
]
検索条件:部分一致
> db_employee_info> db.employee.find( { employeeName: // },{ employeeName:1 } )
[
  { _id: ObjectId('668b87b9e98d52fe42f3f54e'), employeeName: '田村' },
  { _id: ObjectId('668b87b9e98d52fe42f3f54f'), employeeName: '山田' },
  { _id: ObjectId('668b87b9e98d52fe42f3f553'), employeeName: '吉田' },
  { _id: ObjectId('668bacdf05dbdfe7c7f3f54f'), employeeName: '大田' }
]
検索条件:前方一致
> db_employee_info> db.employee.find( { employeeName: /^/ },{ employeeName:1 } )
[ { _id: ObjectId('668b87b9e98d52fe42f3f54e'), employeeName: '田村' } ]
検索条件:後方一致
> db_employee_info> db.employee.find( { employeeName: /$/ },{ employeeName:1 } )
[
  { _id: ObjectId('668b87b9e98d52fe42f3f54f'), employeeName: '山田' },
  { _id: ObjectId('668b87b9e98d52fe42f3f553'), employeeName: '吉田' },
  { _id: ObjectId('668bacdf05dbdfe7c7f3f54f'), employeeName: '大田' }
]

検索条件(範囲指定)

検索条件:以下
> db_employee_info> db.employee.find({age: { $lte: 30 } },{ employeeName:1, age:1 } )
[
  {
    _id: ObjectId('668b87b9e98d52fe42f3f54e'),
    employeeName: '田村',
    age: 30
  },
  {
    _id: ObjectId('668b87b9e98d52fe42f3f551'),
    employeeName: '佐藤',
    age: 23
  }
]
検索条件:未満
> db_employee_info> db.employee.find({age: { $lt: 30 } },{ employeeName:1, age:1 } )
[
  {
    _id: ObjectId('668b87b9e98d52fe42f3f551'),
    employeeName: '佐藤',
    age: 23
  }
]
検索条件:以上
> db_employee_info> db.employee.find( { age: { $gte: 36 } },{ employeeName:1, age:1 } )
[
  {
    _id: ObjectId('668b87b9e98d52fe42f3f550'),
    employeeName: '中山',
    age: 37
  },
  {
    _id: ObjectId('668babfb05dbdfe7c7f3f54e'),
    employeeName: '上野',
    age: 36
  },
  {
    _id: ObjectId('668bacdf05dbdfe7c7f3f54f'),
    employeeName: '大田',
    age: 36
  }
]
検索条件:より大きい
> db_employee_info> db.employee.find( { age: { $gt: 36 } },{ employeeName:1, age:1 } )
[
  {
    _id: ObjectId('668b87b9e98d52fe42f3f550'),
    employeeName: '中山',
    age: 37
  }
]
検索条件:範囲指定
> db_employee_info> db.employee.find(
                        { age: { $gte: 30, $lte: 32 } },
                        { employeeName:1, age:1 }
                    )
[
  {
    _id: ObjectId('668b87b9e98d52fe42f3f54e'),
    employeeName: '田村',
    age: 30
  },
  {
    _id: ObjectId('668b87b9e98d52fe42f3f54f'),
    employeeName: '山田',
    age: 31
  }
]
検索条件:and
db_employee_info> db.employee.find(
                            { $and: [ 
                                { employeeName: // },
                                {age: {$lte: 32 } } 
                                ] },
                            { employeeName:1, age:1 }
                        )
[
  {
    _id: ObjectId('668b87b9e98d52fe42f3f54e'),
    employeeName: '田村',
    age: 30
  },
  {
    _id: ObjectId('668b87b9e98d52fe42f3f54f'),
    employeeName: '山田',
    age: 31
  }
]
検索条件:or
> db_employee_info> db.employee.find(
                            { $or: [
                                { employeeName: /田村/ },
                                { age: { $gte: 37 } } 
                                ] },
                            { employeeName:1, age:1 }
                        )
[
  {
    _id: ObjectId('668b87b9e98d52fe42f3f54e'),
    employeeName: '田村',
    age: 30
  },
  {
    _id: ObjectId('668b87b9e98d52fe42f3f550'),
    employeeName: '中山',
    age: 37
  }
]
検索条件:「skill -> name」のフィールドを持っているデータ
> db_employee_info> db.employee.find({"skill.name": {$exists: true}},{employeeName:1, skill:1})
[
  {
    _id: ObjectId('668bacdf05dbdfe7c7f3f54f'),
    employeeName: '大田',
    skill: [
      { name: 'Oracle', level: 3 },
      { name: 'MySQL', level: 2 },
      { name: 'Redis', level: 1 },
      { name: 'MongoDB', level: 5 }
    ]
  }
]
検索条件:指定した要素数をもつドキュメントを検索する
> db_employee_info> db.employee.find({skill: {$size: 4}},{employeeName:1, skill:1})
[
  {
    _id: ObjectId('668babfb05dbdfe7c7f3f54e'),
    employeeName: '上野',
    skill: [ 'Oracle', 'MySQL', 'Redis', 'MongoDB' ]
  },
  {
    _id: ObjectId('668bacdf05dbdfe7c7f3f54f'),
    employeeName: '大田',
    skill: [
      { name: 'Oracle', level: 3 },
      { name: 'MySQL', level: 2 },
      { name: 'Redis', level: 1 },
      { name: 'MongoDB', level: 5 }
    ]
  }
]
検索結果をソートする
> db_employee_info> db.employee.find(
                            {},
                            { _id: 0, employeeName: 1, age: 1 }
                        ).sort(
                            { age: 1 }
                        )
[
  { employeeName: '佐藤', age: 23 },
  { employeeName: '田村', age: 30 },
  { employeeName: '山田', age: 31 },
  { employeeName: '佐々木', age: 33 },
  { employeeName: '吉田', age: 35 },
  { employeeName: '上野', age: 36 },
  { employeeName: '大田', age: 36 },
  { employeeName: '中山', age: 37 }
]
検索結果の件数を制限する
> db_employee_info> db.employee.find(
                            {},
                            { _id: 0, employeeName: 1, age: 1 }
                        ).sort(
                            { age: 1 }
                        ).limit(2)
[
  { employeeName: '佐藤', age: 23 },
  { employeeName: '田村', age: 30 }
]
検索結果で取得する開始位置を指定する  ※検索結果は0番目から始まる
> db_employee_info> db.employee.find(
                            {},
                            { _id: 0, employeeName: 1, age: 1 }
                        ).sort(
                            { age: 1 }
                        ).limit(2).skip(2)
[
  { employeeName: '山田', age: 31 },
  { employeeName: '佐々木', age: 33 }
]

最後に

今回はここまでとします。RDBのSQLと違い、JSON形式のデータを検索する機能(要素数による検索、フィールド名による検索)が用意されているため、RDBとはまた違った活用方法があると感じました。
他にも色々な検索条件があるようなので、便利な検索条件があればコメントいただけるとうれしいです。

34
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
6