Package jp.ameba.mongo

Source Code of jp.ameba.mongo.MongoCursor

package jp.ameba.mongo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import jp.ameba.mongo.protocol.Delete;
import jp.ameba.mongo.protocol.GetMore;
import jp.ameba.mongo.protocol.KillCursors;
import jp.ameba.mongo.protocol.Query;
import jp.ameba.mongo.protocol.Response;

import org.bson.BSONObject;
import org.bson.BasicBSONObject;

/**
* カーソル処理を行ないます。
* カーソルそのものはスレッドセーフではないため、
* 各スレッドは別個にクエリを作成し、取得する必要があります。
*
* @author suguru
*/
public class MongoCursor implements Iterable<BSONObject>, Iterator<BSONObject> {
 
  // MongoClient
  private MongoConnection conn;
 
  // 対象のデータベース名
  private String databaseName;
 
  // 対象のコレクション名
  private String collectionName;
 
  // 検索に利用したクエリオブジェクト
  private Query query;
 
  // 検索のためのフィールド条件
  private BSONObject selector;
 
  // 検索のための特殊フィールド
  private BSONObject special;
 
  // ソートのためのフィールド
  private BSONObject orderby;
 
  // クエリーインデクスヒント
  private BSONObject hints;
 
  // 取得するフィールド一覧
  private BSONObject fields;
 
  // 使用するインデクスに対する検索最小値
  private BSONObject min;
 
  // 使用するインデクスに対する検索最大値
  private BSONObject max;
 
  // 結果を一度にフェッチするサイズ
  private int batchSize = 100;
 
  // 最初にスキップする件数
  private int firstSkip = 0;
 
  // カーソルから取得した最新の結果
  private Response lastResult;
 
  // 現在選択中のオブジェクト
  private BSONObject currentObject;
 
  // 現在の結果におけるインデクス
  private int indexInResult = 0;
 
  // カーソル最終位置への到達フラグ
  private boolean finished = false;
 
  // カーソルのクローズフラグ
  private boolean closed = false;
 
  // 現在の取得件数
  private int position = 0;
 
  MongoCursor(
      MongoConnection conn,
      String databaseName,
      String collectionName) {
    this.conn = conn;
    this.databaseName = databaseName;
    this.collectionName = collectionName;
  }
 
  /**
   * カーソルの対象としているデータベース名を取得します。
   * @return
   */
  public String getDatabaseName() {
    return databaseName;
  }
 
  /**
   * カーソルの対象としているコレクション名を取得します。
   * @return
   */
  public String getCollectionName() {
    return collectionName;
  }
 
  /**
   * 最大取得件数を設定します。
   *
   * @param limit
   * @return
   */
  public MongoCursor limit(int limit) {
    return special("$maxScan", limit);
  }
 
  /**
   * 取得フィールドを設定・追加します。
   * @param field
   * @return
   */
  public MongoCursor field(String field) {
    return field(field, 1);
  }
 
  /**
   * 取得フィールドを設定・追加します。
   * @param field
   * @param value
   * @return
   */
  public MongoCursor field(String field, Object value) {
    if (fields == null) {
      fields = new BasicBSONObject();
    }
    fields.put(field, value);
    return this;
  }
 
  /**
   * クエリインデクスヒントとして使用する
   * フィールド名を指定します。
   *
   * @param field
   * @return
   */
  public MongoCursor hint(String field) {
    if (hints == null) {
      hints = new BasicBSONObject();
      special.put("$hint", hints);
    }
    hints.put(field, 1);
    return this;
  }
 
  /**
   * 使用するインデクスに対する最小値を設定します。
   * ここで使用するフィールドは hint メソッドによって
   * 指定されている必要があります。
   *
   * @param field
   * @param value
   * @return
   */
  public MongoCursor min(String field, Object value) {
    if (min == null) {
      min = new BasicBSONObject();
      special.put("$min", min);
    }
    min.put(field, value);
    return this;
  }
 
  /**
   * 使用するインデクスに対する最大値を設定します。
   * ここで使用するフィールドは hint メソッドによって
   * 指定されている必要があります。
   *
   * @param field
   * @param value
   * @return
   */
  public MongoCursor max(String field, Object value) {
    if (max == null) {
      max = new BasicBSONObject();
      special.put("$max", max);
    }
    max.put(field, value);
    return this;
  }
 
  /**
   * インデクスキーのみの返却を設定します。
   * @param returnKey
   * @return
   */
  public MongoCursor returnKey() {
    return special("$returnKey", true);
  }
 
  /**
   * 結果をフェッチする際に一括で取得する件数を設定します。
   * @param batchSize
   * @return
   */
  public MongoCursor batchSize(int batchSize) {
    this.batchSize = batchSize;
    return this;
  }
 
  /**
   * 結果取得の際に最初にスキップする件数を設定します。
   * @param skip
   * @return
   */
  public MongoCursor firstSkip(int firstSkip) {
    this.firstSkip = firstSkip;
    return this;
  }
 
  /**
   * 指定フィールドのソートオーダーを指定します。
   * @param key
   * @param asc
   * @return
   */
  public MongoCursor sort(String field, boolean asc) {
    if (orderby == null) {
      orderby = new BasicBSONObject();
      special("$orderby", orderby);
    }
    orderby.put(field, asc ? 1 : -1);
    return this;
  }
 
  /**
   * クエリの実行計画を取得するための設定をします。
   * @return
   */
  public MongoCursor explain() {
    return special("$explain", true)
  }
 
  /**
   * クエリに対する slaveOk フラグを設定します。
   * @return
   */
  public MongoCursor slaveOk() {
    query.slaveOk(true);
    return this;
  }
 
  /**
   * クエリに対する Talable フラグを設定します。
   * @return
   */
  public MongoCursor tailable() {
    query.tailableCursor(true);
    return this;
  }
 
  /**
   * クエリに対する カーソルタイムアウトを無効にします。
   * @return
   */
  public MongoCursor noCursorTimeout() {
    query.noCursorTimeout(true);
    return this;
  }
 
  /**
   * クエリに対するデータ待機を有効にします。
   * @return
   */
  public MongoCursor awaitData() {
    query.awaitData(true);
    return this;
  }
 
  /**
   * クエリに対する Exhaust オプションを有効にします。
   * @return
   */
  public MongoCursor exhaust() {
    query.exhaust(true);
    return this;
  }
 
  /**
   * クエリのスナップショットを設定します。
   * @return
   */
  public MongoCursor snapshot() {
    return special("$snapshot", true);
  }
 
  /**
   * 特殊フィールド条件を追加します。
   * @param name
   * @param value
   * @return
   */
  public MongoCursor special(String name, Object value) {
    if (this.special == null) {
      this.special = new BasicBSONObject();
    }
    special.put(name, value);
    return this;
  }
 
  /**
   * クエリ条件を保持するマップオブジェクトを取得します。
   * @return
   */
  public BSONObject selector() {
    if (this.selector == null) {
      this.selector = new BasicBSONObject();
    }
    return this.selector;
  }
 
  /**
   * クエリ条件を追加します。
   * @param field
   * @param queryValue
   * @return
   */
  public MongoCursor selector(String field, Object queryValue) {
    if (this.selector == null) {
      this.selector = new BasicBSONObject();
    }
    this.selector.put(field, queryValue);
    return this;
  }
 
  /**
   * 指定のクエリ条件を設定します。
   * @param selector
   * @return
   */
  public MongoCursor selector(BSONObject selector) {
    if (this.selector == null) {
      this.selector = selector;
    } else {
      this.selector.putAll(selector);
    }
    return this;
  }
 
  /**
   * 詳細なクエリ条件を追加します。
   * @param field
   * @param criteriaKey
   * @param criteriaValue
   * @return
   */
  public MongoCursor selector(String field, String criteriaKey, Object criteriaValue) {
    if (this.selector == null) {
      this.selector = new BasicBSONObject();
    }
    BSONObject criteria = (BSONObject) selector.get(field);
    if (criteria == null) {
      criteria = new BasicBSONObject();
      selector.put(field, criteria);
    }
    criteria.put(criteriaKey, criteriaValue);
    return this;
  }
 
  /**
   * 指定の値より大きな値を検索条件とします。
   * @param field
   * @param value
   * @return
   */
  public MongoCursor greaterThan(String field, Object value) {
    return selector(field, "$gt", value);
  }
 
  /**
   * 指定の値より小さな値を検索条件とします。
   * @param field
   * @param value
   * @return
   */
  public MongoCursor lesserThan(String field, Object value) {
    return selector(field, "$lt", value);
  }
 
  /**
   * 指定の値と等しいか、大きな値を検索条件とします。
   * @param field
   * @param value
   * @return
   */
  public MongoCursor greaterThanEquals(String field, Object value) {
    return selector(field, "$gte", value);
  }
 
  /**
   * 指定の値と等しいか、小さい値を検索条件とします。
   * @param field
   * @param value
   * @return
   */
  public MongoCursor lesserThanEquals(String field, Object value) {
    return selector(field, "$lte", value);
  }
 
  /**
   * 指定の値を不等であることを検索条件とします。
   * @param field
   * @param value
   * @return
   */
  public MongoCursor notEquals(String field, Object value) {
    return selector(field, "$ne", value);
  }
 
  /**
   * 指定のフィールドが存在する行のみ検索条件とします。
   * @param field
   * @return
   */
  public MongoCursor exists(String field) {
    return selector(field, "$exists", true);
  }
 
  @Override
  public boolean hasNext() {
    // 終了済みのカーソルチェック
    if (finished || closed) {
      return false;
    }
    // 最後の結果が存在しない場合は、クエリを投げて取得する
    if (lastResult == null) {
      if (query == null) {
        BSONObject queryObject = null;
        if (selector == null) {
          selector = new BasicBSONObject();
        }
        if (special != null) {
          special.put("$query", selector);
          queryObject = special;
        } else {
          queryObject = selector;
        }
        query = new Query(databaseName, collectionName, firstSkip, batchSize, queryObject, fields);
      }
      lastResult= conn.query(query);
      // 最終結果がなければ、次はない
      if (lastResult.getNumberReturned() == 0) {
        finished = true;
        return false;
      }
    }
    // ドキュメント一覧取得
    List<BSONObject> documents = lastResult.getDocuments();
    if (documents == null || indexInResult >= documents.size()) {
      lastResult = conn.getMore(new GetMore(
          databaseName,
          collectionName,
          batchSize,
          lastResult.getCursorId()
      ));
      indexInResult = 0;
      if (lastResult.getNumberReturned() == 0) {
        finished = true;
        close();
        return false;
      }
    }
    return true;
  }
 
  /**
   * このカーソルによって取得可能なすべてのオブジェクトを
   * {@link List} として取得します。
   *
   * @return
   */
  public List<BSONObject> asList() {
    List<BSONObject> list = new ArrayList<BSONObject>();
    for (BSONObject object : this) {
      list.add(object);
    }
    return list;
  }
 
  @Override
  public BSONObject next() {
    if (!hasNext()) {
      return null;
    }
    List<BSONObject> documents = lastResult.getDocuments();
    currentObject = documents.get(indexInResult);
    position++;
    indexInResult++;
    return currentObject;
  }
 
  @Override
  public void remove() {
    if (currentObject != null) {
      Delete delete = new Delete(
          databaseName,
          collectionName,
          new BasicBSONObject("_id", currentObject.get("_id"))
      );
      conn.delete(delete);
    }
  }
 
  @Override
  public Iterator<BSONObject> iterator() {
    return this;
  }
 
  @Override
  protected void finalize() throws Throwable {
    close();
  }

  /**
   * このカーソルのクローズ処理を行います。
   * サーバーに対して KILL_CURSOR を送信し、
   * リソースの解放を実施します。
   */
  public void close() {
    if (!closed) {
      if (lastResult != null) {
        conn.killCursors(new KillCursors(lastResult.getCursorId()));
      }
      closed = true;
    }
  }
}
TOP

Related Classes of jp.ameba.mongo.MongoCursor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.