1

Im using createCompsiteKey, and getSateByRange only returns {"done":true}. I tried to replace createCompsiteKey with concat key part to make the key as follows. getSateByRange only returns {"done":true}, I'm using "fabric-shim" v1.4.0 and "fabric-contract-api" v1.4.0. "fabric-peer" image is 1.4.6.

Code for addState to db is below:

class StateList {
    async addState(state){
    let keyParts = state.getSplitKey();
    let keyPrefix = (String)(keyParts.slice(0,1));
    let keyOthers = keyParts.slice(1);
    
    /*. comment createCompositeKey
    let key = this.ctx.stub.createCompositeKey(keyPrefix, keyOthers);
    */
    let key = keyParts.map(part => part).join('');

    let data = State.serialize(state);
    await this.ctx.stub.putState(key, data);
   }
}

class State {
    constructor(stateClass, keyParts) {
        this.class = stateClass;
        this.key = State.makeKey(keyParts);
    }
    static makeKey(keyParts) {
        return keyParts.map(part => part).join(':');
    }
    static splitKey(key){
        return key.split(':');
    }
}

async getDevCollectByRange(ctx, startKey, endKey){
    let args = [];
    args[0] = startKey;
    args[1] = endKey;
    let xiotdatadevlist = await ctx.xiotDataDevList.getDevByRange(args);
    return Buffer.from(xiotdatadevlist);
}

async getAllResults(iterator){
    let allResults = [];
        while (true) {
        const res = await iterator.next();

        if (res.value && res.value.value.toString()) {
            console.log(res.value.value.toString('utf8'));

            const Key = res.value.key;
            let Record;
            try {
                Record = JSON.parse(res.value.value.toString('utf8'));
            } catch (err) {
                console.log(err);
                Record = res.value.value.toString('utf8');
            }
            allResults.push({ Key, Record });
        }
        if (res.done) {
            await iterator.close();
            return allResults;
        }
    }       
}

async getObjectsByRange(args) {

    if (args.length < 2) {
        throw new Error('Incorrect number of arguments. Expecting 2');
    }
    // date 
    const startKey = args[0];
    const endKey = args[1];
    
    const resultsIterator = await this.ctx.stub.getStateByRange(startKey, endKey);
    let results = await this.getAllResults(resultsIterator, false);

    return Buffer.from(JSON.stringify(results));
}

If I use createCompsiteKey, how can getSateByRange find my records? Or what condition fabric key must meet?

any suggestion, Thank you.

Serg
  • 2,346
  • 3
  • 29
  • 38
  • Unable to understand your question. Please narrow the problem and remove code lines which are not helping in describing your question. – Kartik Chauhan Jul 29 '20 at 11:00
  • sorry. my problem is same to the post https://stackoverflow.com/questions/57806267/trouble-getting-response-from-hyperledger-fabric-getstatebyrange-and-getstatebyp but I can not get clear solution – user14014310 Jul 29 '20 at 12:55
  • I plan to comment the post, but I not 50 reputation to comment, so I summit new post – user14014310 Jul 29 '20 at 13:20
  • Your question statement is a little unclear. could you please help me in understanding why aren't you using the method "createCompositeKey"? Why have you commented it out? – Kartik Chauhan Jul 29 '20 at 15:03
  • if using createCompositeKey, for example, I my code: Suppose keyParts is [XIOT, BATCH, 1,20200708123059], keyPrefix = XIOT, keyOthers=BATCH, 1,20200708123059 then createCompositeKey(keyPrefix, keyOthers) output is XIOT:BATCH:1:20200708123059 when getSateByRange (startKey = "XIOT:BATCH:1:20200708123059" , endKey="XIOT:BATCH:1:20200820123059") , stub.getStateByRange's response iterator is [91, 93], which is not correct result – user14014310 Jul 29 '20 at 15:35
  • https://stackoverflow.com/questions/57806267/trouble-getting-response-from-hyperledger-fabric-getstatebyrange-and-getstatebyp owner of the link not choose to use createCompositeKey, she say " I was using the stub.createCompositeKey but it was creating the keys with a u0000 character at the begining of the key and the method stub.getStateByRange couldn't find anything". – user14014310 Jul 29 '20 at 15:38

1 Answers1

0

In previous versions of Fabric, getStateByRange API used to return composite keys even when doing a range query on simple keys. For example, the following range query on marble02 chaincode example returned both simple keys such as marble2, marble3, and composite keys such as color~namebluemarble2, color~namebluemarble2 where it should have returned only marble2 and marble3.

$ peer chaincode query -n mycc1 -v 0 -c {"Args":["getMarblesByRange","a","z"]} -o 127.0.0.1:7050 -C ch1

Query Result:

[
    {"Key":"color~namebluemarble3", "Record":}
    {"Key":"color~nameredmarble2", "Record":},
    {"Key":"marble2", "Record":{"docType":"marble","name":"marble2","color":"red","size":50,"owner":"tom"}},
    {"Key":"marble3", "Record":{"docType":"marble","name":"marble3","color":"blue","size":70,"owner":"tom"}}
]

There was no way for Fabric to differentiate between a simple or composite so that GetStateByRange() could return only simple keys.

Composite keys have an objectType prefix. Each part of composite key is delimited by null character for example chaincodeid 0x00 objectType 0x00 ck1 0x00 ck2 0x00. This design ensured that various composite key types have an objectType namespace to guarantee no collisions across types. You can check this yourself by hovering over copy icon on any CouchDB record which have a composite key like in the image below. couchdb-composite-key

Now, getStateByRange() returns only simple keys and getStateByPartialCompositeKey() returns only composite keys. The namespaces for simple keys and composite keys are different to avoid collisions. For more information on this, you can refer to this thread, where Fabric maintainers had a discussion on how to approach this issue.

If you do an unbounded range query on start & end, you won't see any composite key in the results. I tried it myself and these were the results that I received.

peer chaincode query -n marbles -C mychannel -c '{"Args":["getMarblesByRange", "", ""]}'

Output:

[
    {"Key":"azurite","Record": 
        {"color":"yellow","docType":"marble","name":"azurite","owner":"john","size":2}
    },
    {"Key":"marble1","Record": 
        {"color":"red","docType":"marble","name":"marble1","owner":"tom","size":50}
    },
    {"Key":"marble2","Record": 
        {"color":"blue","docType":"marble","name":"marble2","owner":"tom","size":70}
    }
]

However, when I kept \u0000 as my start key, I received records that had composite key as well.

peer chaincode query -n marbles4 -C mychannel -c '{"Args":["getMarblesByRange", "\u0000", ""]}'

Output:

[
    {"Key":"\u0000color~name\u0000blue\u0000marble2\u0000","Record":"\u0000"}, 
    {"Key":"\u0000color~name\u0000red\u0000marble1\u0000","Record":"\u0000"}, 
    {"Key":"\u0000color~name\u0000yellow\u0000azurite\u0000","Record":"\u0000"}, 
    {"Key":"azurite","Record": 
        {"color":"yellow","docType":"marble","name":"basil","owner":"john","size":2}
    },
    {"Key":"marble1","Record": 
        {"color":"red","docType":"marble","name":"marble1","owner":"tom","size":50}
    },
    {"Key":"marble2","Record": 
        {"color":"blue","docType":"marble","name":"marble2","owner":"tom","size":70}
    }
]

So, in conclusion, I think you shouldn't use getStateByRange API, but getStateByPartialCompositeKey to fetch records which have composite keys.

Kartik Chauhan
  • 2,779
  • 5
  • 28
  • 39
  • 1
    if using getStateByRange ,I think that simple key add valid prefix to avoid [getMarblesByRange","a","z"],which also lead to same aim with CompositeKey. getStateByPartialCompositeKey is Partial order query, which may enlarge query range and need additional work to definite range. another new getStateByCompositeKeyRange is better. I need make more test. Thanks you Kartik very much. – user14014310 Jul 30 '20 at 01:37
  • Please consider this as the accepted answer if it answers your question. Thank you. – Kartik Chauhan Jul 30 '20 at 01:56
  • yeh, it help me much. but I can not add 1 score, when I add 1 socre, "Thanks for the feedback! Votes cast by those with less than 15 reputation are recorded, but do not change the publicly displayed post score." – user14014310 Jul 30 '20 at 06:02
  • No, I'm asking you to just mark this answer as accepted answer if it answers your question. You can see a checkmark icon just below the upvote/downvote icons. You can click on it to make this answer as the accepted answer. – Kartik Chauhan Jul 30 '20 at 06:41