在Fabric鏈碼中進行前綴批查詢

用過Fabric的都知道,在Fabric中的狀態數據庫提供了Couchdb和Leveldb兩種實現,一般我們都會使用Couchdb作爲狀態數據庫的默認實現,主要是因爲Couchdb可以進行富查詢。但是在某些情況下我們只能採用Leveldb的情況下,我們無法使用富查詢,那麼怎麼辦?我們可以利用Leveldb適合前綴查詢的特點進行前綴查詢,而且由於Leveldb底層結構的特點,進行前綴查詢的效率是特別高的。

要進行前綴查詢,那麼我們在PutState的時候要合理設計前綴值,從而能夠利用前綴查詢。以一個會議簽到存證系統爲例,我們在Fabric的鏈碼中設計了兩個對象Meeting和CheckinLog。

會議對象Meeting的存證我們設計Key爲:“Meeting_”+會議ID,然後PutState將會議的JSON存入Fabric中。

簽到記錄對象CheckinLog的存證,我們設計Key爲:”Checkin_”+會議ID+”_”+用戶ID,然後調用PutState將CheckinLog這個對象的Json作爲Value存入到Fabric中。

接下來是對某個會議的簽到記錄的查詢了。這麼我們知道會議ID的情況下,查詢簽到記錄返回的是一個集合,那麼我們可以基於stub.GetStateByRange接口來進行查詢,該操作的核心就是要構造其兩個參數startKey和endKey。以下是代碼實現,主要用到了BytesPrefix函數用於計算endKey,該函數是在github.com/syndtr/goleveldb/leveldb/util有的,我們直接摘抄出來即可。

//根據會議ID,返回本次會議的簽到記錄列表
func QueryCheckinLogsByMeetingId(stub shim.ChaincodeStubInterface, meetingId int) ([]*CheckinLog, error) {
    startKey:=fmt.Sprintf( "Checkin_%d_",meetingId)
    endKey:=string(BytesPrefix([]byte(startKey)))
    resultsIterator, err:= stub.GetStateByRange(startKey,endKey)
    defer resultsIterator.Close()
    if err != nil {
        return nil, err
    }
    result:=[]*CheckinLog{}
    for resultsIterator.HasNext() {
        queryResponse,err:= resultsIterator.Next()
        if err != nil {
            return nil, err
        }
        row:=&CheckinLog{}
        json.Unmarshal(queryResponse.Value,row)
        result=append(result,row)
    }
    return result, nil
}

//計算GetStateByRange時的endKey,該函數摘自:github.com/syndtr/goleveldb/leveldb/util
func BytesPrefix(prefix []byte) []byte {
    var limit []byte
    for i := len(prefix) - 1; i >= 0; i-- {
        c := prefix[i]
        if c < 0xff {
            limit = make([]byte, i+1)
            copy(limit, prefix)
            limit[i] = c + 1
            break
        }
    }
    return limit
}

 

就是這樣的邏輯,我們就可以在Fabric鏈碼中通過前綴進行批量查詢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章