Closed13

LiteDB(v5.0.15)を使ってみる

ピン留めされたアイテム
rakrak

ドキュメント系。

rakrak

LiteDB Viewerのありか。exeもpushされているのでcloneすれば使える。
https://github.com/mbdavid/LiteDB.Studio/tree/release_v1.0.3
https://github.com/mbdavid/LiteDB.Studio/blob/release_v1.0.3/LiteDB.Studio/LiteDB.Studio.exe

公式ドキュメントは以下。
https://www.nuget.org/packages/LiteDB/

最新(LiteDB v5)のはLiteDB.Studioっていう名前で新しくなっている。
サジェストとかにはLiteDB Viewerって出てくるから探すのに手間取った。

rakrak

LiteDBにレコードをinsertするときに、以下のようにプロパティを渡す必要があるが、このときジェネリクスはそのプロパティclassの型と一致していないとidの自動採番でエラーになる。

// OKパターン
public class TestProperty {
    public int id { get; set; } // 自動採番
    public string text { get; set; }
}

public static class TestOk{
    public static void DbTest() {
        using (var db = new LiteDatabase("testDatabase.db")) {
            var col= db.GetCollection<TestProperty>("test");
            col.Insert(new TestProperty { text = "aaa" });
        }
    }
}
// NGパターン
public interface ITestProperty {
}

public class TestNgProperty : ITestProperty {
    public int id { get; set; }
    public string text { get; set; }
}

public static class TestNG {
    public static void DbTest() {
        using (var db = new LiteDatabase("testDatabase.db")) {
            // 実装元のinterfaceを型にしているがNG
            var col = db.GetCollection<ITestProperty>("test");
            col.Insert(new TestNgProperty { text = "aaa" });
        }
    }
}

// エラー内容
// LiteDB.LiteException: 'Cannot insert duplicate key in unique index '_id'. The duplicate value is '0'.'

以下Issuesを参考。
LiteDBではジェネリクスの型を見て、各プロパティの型を判断しているとのこと。
https://github.com/mbdavid/LiteDB/issues/1117

rakrak

BsonDocumentでやることにした。(抜粋)

    // Typeを使ってプロパティの一覧を取得
    PropertyInfo[] properties = Type.GetType(this.propertyClass.FullName).GetProperties();
    var propClassObj = Activator.CreateInstance(this.propertyClass);

    foreach (var prop in properties) {
      prop.SetValue(propClassObj, data.GetValueOrDefault(prop.Name));
    }

    var bson = BsonMapper.Global.ToDocument(propClassObj));
    col.Insert(bson);
  1. プロパティのクラスを作る
  2. プロパティ全てをloopでDictionary型のdata変数と突き合わせ、プロパティに設定
  3. BsonMapperを使用し、BsonDocument型のオブジェクトを作成
  4. 作成したBsonDocumentオブジェクトでinsert
rakrak

AutoId はリレーショナル データベースのシーケンスと同様に使用できますが、動作が少し異なります。AutoId は保持されず、ファイルを再度開いたときにメモリ内に再作成する必要があるため、以前に削除されたドキュメントの ID が再利用される可能性があります。

https://www.litedb.org/docs/object-mapping/

rakrak

IN句をIdで絞る場合やり方は?

// this.DataListはList<Dictionary<string, object>>
List<BsonValue> Ids = this.DataList.Select(dict => new BsonValue(dict["Id"])).ToList();

// {`$.Id IN [{$oid:"63f9fb1c7e28c3014a4fdedc"}]` [In]} が入っている
var query = Query.In("Id", new BsonArray(Ids));

// これの結果が削除件数0
col.DeleteMany(query); 
rakrak

プロパティクラスでIdは以下のように定義していたが、

public ObjectId Id { get; set; }

LiteDBの列を覗くと列名は_idだった。
上記コードのQuery.In("_id", new BsonArray(Ids));にしたら削除された

rakrak

特定のIDを持ったレコードで、特定のフィールドにnullを設定したい場合の方法。
以下はIN句を使ってマッチしたレコードのFieldNameというフィールドをnullに置き換えている。

List<BsonValue> Ids = // _idの値を持ったList<BsonValue>変数
string fieldName = "FieldName";
var query = Query.In(fieldName , new BsonArray(Ids));

//~LiteDatabase litedb = new LiteDatabase("collectionName")などの処理~

col.UpdateMany("{"+fieldName +":$unset}",  query)

{FieldName:$unset}この形式の文字列と条件(クエリ)をUpdateManyに渡してやればいい

rakrak

LiteDBViewerを使用して置き換えるだけで構わないのであれば、LiteDBViewerを起動し普通にSQLクエリを投げればOK

update collection
set FieldName = null
where FieldName= "hoge"
rakrak

ObjectIdのフィールドをUpdateManyする方法

List<BsonValue> Ids = // _idの値を持ったList<BsonValue>変数
string fieldName = "FieldName";
var query = Query.In(fieldName , new BsonArray(Ids));

//~LiteDatabase litedb = new LiteDatabase("collectionName")などの処理~

string updateQuery = "{ObjectIdField:OBJECTID('IDを設定')}";
col.UpdateMany(updateQuery, query);

以下に記載されているFunctionを使って変換している。
https://github.com/mbdavid/LiteDB/wiki/Expressions#datatype

そのままObjectIdを設定するとstring型で登録されるので注意。

rakrak

配列の値をINする方法。

// プロパティクラス
public class Data {
    public ObjectId _id { get; set; }
    public int Number { get; set; }
    public List<int>? SubNumberList { get; set; }
}
// 検索する方法
// SubIdListフィールドの値として1もしくは2を持つレコードがヒットする
col.Find("$.SubNumberList[*] ANY IN [1,2]"); 
rakrak

objectidの場合のメモ

OBJECTID()でObjectIdの値を囲む

ObjectId oid1 = hoge;
ObjectId oid2 = huga;

col.Find("$.SubIdList[*] ANY IN [OBJECTID('" + oid1 + "'), OBJECTID('" + oid2 + "')]");
このスクラップは2ヶ月前にクローズされました