Skip to content

Commit dbfa920

Browse files
cendhuChris Elder
authored andcommitted
[FAB-7752] rm chaincodeid frm couchdb doc envelope
Now that we create one database per chaincode, the chaincodeID that gets implicitly added to the json document, to queries, and to indexes is not required and might cause issues for user. Hence, this CR removes the implicit addition of chaincodeID to docs, queries, and indexes. Change-Id: Ie8ac9240fc709e0870ec25cddd49e3c2fc4ba6b2 Signed-off-by: senthil <cendhu@gmail.com>
1 parent ea3bf3c commit dbfa920

File tree

5 files changed

+33
-112
lines changed

5 files changed

+33
-112
lines changed

core/ledger/kvledger/txmgmt/statedb/statecouchdb/query_wrapper.go

Lines changed: 5 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ All fields in the selector must have "data." prepended to the field names
4141
Fields listed in fields key will have "data." prepended
4242
Fields in the sort key will have "data." prepended
4343
44-
- The query will be scoped to the chaincodeid
45-
4644
- limit be added to the query and is based on config
4745
- skip is defaulted to 0 and is currently not used, this is for future paging implementation
4846
@@ -56,12 +54,12 @@ Source Query:
5654
"sort": ["size", "color"]}
5755
5856
Result Wrapped Query:
59-
{"selector":{"$and":[{"chaincodeid":"marble"},{"data.owner":{"$eq":"tom"}}]},
57+
{"selector":{"data.owner":{"$eq":"tom"}},
6058
"fields": ["data.owner","data.asset_name","data.color","data.size","_id","version"],
6159
"sort":["data.size","data.color"],"limit":10,"skip":0}
6260
6361
*/
64-
func ApplyQueryWrapper(namespace, queryString string, queryLimit, querySkip int) (string, error) {
62+
func ApplyQueryWrapper(queryString string, queryLimit, querySkip int) (string, error) {
6563

6664
//create a generic map for the query json
6765
jsonQueryMap := make(map[string]interface{})
@@ -77,26 +75,17 @@ func ApplyQueryWrapper(namespace, queryString string, queryLimit, querySkip int)
7775
//traverse through the json query and wrap any field names
7876
processAndWrapQuery(jsonQueryMap)
7977

80-
//if "fields" are specified in the query, then add the "_id", "version" and "chaincodeid" fields
78+
//if "fields" are specified in the query, then add the "_id", and "version"fields
8179
if jsonValue, ok := jsonQueryMap[jsonQueryFields]; ok {
8280
//check to see if this is an interface map
8381
if reflect.TypeOf(jsonValue).String() == "[]interface {}" {
8482

85-
//Add the "_id", "version" and "chaincodeid" fields, these are needed by default
83+
//Add the "_id", and "version" fields, these are needed by default
8684
jsonQueryMap[jsonQueryFields] = append(jsonValue.([]interface{}),
87-
"_id", "version", "chaincodeid")
85+
"_id", "version")
8886
}
8987
}
9088

91-
//Check to see if the "selector" is specified in the query
92-
if jsonValue, ok := jsonQueryMap[jsonQuerySelector]; ok {
93-
//if the "selector" is found, then add the "$and" clause and the namespace filter
94-
setNamespaceInSelector(namespace, jsonValue, jsonQueryMap)
95-
} else {
96-
//if the "selector" is not found, then add a default namespace filter
97-
setDefaultNamespaceInSelector(namespace, jsonQueryMap)
98-
}
99-
10089
//Add limit
10190
jsonQueryMap[jsonQueryLimit] = queryLimit
10291

@@ -112,48 +101,6 @@ func ApplyQueryWrapper(namespace, queryString string, queryLimit, querySkip int)
112101

113102
}
114103

115-
//setNamespaceInSelector adds an additional hierarchy in the "selector"
116-
//{"owner": {"$eq": "tom"}}
117-
//would be mapped as (assuming a namespace of "marble"):
118-
//{"$and":[{"chaincodeid":"marble"},{"data.owner":{"$eq":"tom"}}]}
119-
func setNamespaceInSelector(namespace, jsonValue interface{},
120-
jsonQueryMap map[string]interface{}) {
121-
122-
//create a array to store the parts of the query
123-
var queryParts = make([]interface{}, 0)
124-
125-
//Add the namespace filter to filter on the chaincodeid
126-
namespaceFilter := make(map[string]interface{})
127-
namespaceFilter["chaincodeid"] = namespace
128-
129-
//Add the context filter and the existing selector value
130-
queryParts = append(queryParts, namespaceFilter, jsonValue)
131-
132-
//Create a new mapping for the new query structure
133-
mappedSelector := make(map[string]interface{})
134-
135-
//Specify the "$and" operator for the parts of the query
136-
mappedSelector["$and"] = queryParts
137-
138-
//Set the new mapped selector to the query selector
139-
jsonQueryMap[jsonQuerySelector] = mappedSelector
140-
141-
}
142-
143-
//setDefaultNamespaceInSelector adds an default namespace filter in "selector"
144-
//If no selector is specified, the following is mapped to the "selector"
145-
//assuming a namespace of "marble"
146-
//{"chaincodeid":"marble"}
147-
func setDefaultNamespaceInSelector(namespace string, jsonQueryMap map[string]interface{}) {
148-
149-
//Add the context filter to filter on the chaincodeid
150-
namespaceFilter := make(map[string]interface{})
151-
namespaceFilter["chaincodeid"] = namespace
152-
153-
//Set the new mapped selector to the query selector
154-
jsonQueryMap[jsonQuerySelector] = namespaceFilter
155-
}
156-
157104
func processAndWrapQuery(jsonQueryMap map[string]interface{}) {
158105

159106
//iterate through the JSON query

core/ledger/kvledger/txmgmt/statedb/statecouchdb/query_wrapper_test.go

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestSimpleQuery(t *testing.T) {
2828

2929
rawQuery := []byte(`{"selector":{"owner":{"$eq":"jerry"}},"limit": 10,"skip": 0}`)
3030

31-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
31+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
3232

3333
//Make sure the query did not throw an exception
3434
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
@@ -49,7 +49,7 @@ func TestQueryWithOperator(t *testing.T) {
4949

5050
rawQuery := []byte(`{"selector":{"$or":[{"owner":{"$eq":"jerry"}},{"owner": {"$eq": "frank"}}]},"limit": 10,"skip": 0}`)
5151

52-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
52+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
5353

5454
//Make sure the query did not throw an exception
5555
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
@@ -72,7 +72,7 @@ func TestQueryWithImplicitOperatorAndExplicitOperator(t *testing.T) {
7272

7373
rawQuery := []byte(`{"selector":{"color":"green","$or":[{"owner":"fred"},{"owner":"mary"}]}}`)
7474

75-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
75+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
7676

7777
//Make sure the query did not throw an exception
7878
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
@@ -97,7 +97,7 @@ func TestQueryWithFields(t *testing.T) {
9797

9898
rawQuery := []byte(`{"selector":{"owner": {"$eq": "tom"}},"fields": ["owner", "asset_name", "color", "size"], "limit": 10, "skip": 0}`)
9999

100-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
100+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
101101

102102
//Make sure the query did not throw an exception
103103
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
@@ -124,7 +124,7 @@ func TestQueryWithSortFields(t *testing.T) {
124124

125125
rawQuery := []byte(`{"selector":{"owner": {"$eq": "tom"}},"fields": ["owner", "asset_name", "color", "size"], "sort": ["size", "color"], "limit": 10, "skip": 0}`)
126126

127-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
127+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
128128

129129
//Make sure the query did not throw an exception
130130
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
@@ -151,7 +151,7 @@ func TestQueryWithSortObjects(t *testing.T) {
151151

152152
rawQuery := []byte(`{"selector":{"owner": {"$eq": "tom"}},"fields": ["owner", "asset_name", "color", "size"], "sort": [{"size": "desc"}, {"color": "desc"}], "limit": 10, "skip": 0}`)
153153

154-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
154+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
155155

156156
//Make sure the query did not throw an exception
157157
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
@@ -191,13 +191,13 @@ func TestQueryLeadingOperator(t *testing.T) {
191191
}
192192
}`)
193193

194-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
194+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
195195

196196
//Make sure the query did not throw an exception
197197
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
198198

199199
//$and operator should be unchanged
200-
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"$and\""), 2)
200+
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"$and\""), 1)
201201

202202
//$gte operator should be unchanged
203203
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"$gte\""), 1)
@@ -221,13 +221,13 @@ func TestQueryLeadingAndEmbeddedOperator(t *testing.T) {
221221
]
222222
}}`)
223223

224-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
224+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
225225

226226
//Make sure the query did not throw an exception
227227
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
228228

229229
//$and operator should be unchanged
230-
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"$and\""), 2)
230+
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"$and\""), 1)
231231

232232
//$gte operator should be unchanged
233233
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"$gte\""), 1)
@@ -266,13 +266,13 @@ func TestQueryEmbeddedOperatorAndArrayOfObjects(t *testing.T) {
266266
}
267267
}`)
268268

269-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
269+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
270270

271271
//Make sure the query did not throw an exception
272272
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
273273

274274
//$and operator should be unchanged
275-
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"$and\""), 2)
275+
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"$and\""), 1)
276276

277277
//$gte operator should be unchanged
278278
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"$gte\""), 1)
@@ -297,7 +297,7 @@ func TestQueryEmbeddedOperatorAndArrayOfValues(t *testing.T) {
297297
}
298298
}`)
299299

300-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
300+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
301301

302302
//Make sure the query did not throw an exception
303303
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
@@ -322,27 +322,12 @@ func TestQueryEmbeddedOperatorAndArrayOfValues(t *testing.T) {
322322

323323
}
324324

325-
//TestQueryNoSelector with no selector specified
326-
func TestQueryNoSelector(t *testing.T) {
327-
328-
rawQuery := []byte(`{"fields": ["owner", "asset_name", "color", "size"]}`)
329-
330-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
331-
332-
//Make sure the query did not throw an exception
333-
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
334-
335-
//check to make sure the default selector is added
336-
testutil.AssertEquals(t, strings.Count(wrappedQuery, "\"selector\":{\"chaincodeid\":\"ns1\"}"), 1)
337-
338-
}
339-
340325
//TestQueryWithUseDesignDoc tests query with index design doc specified
341326
func TestQueryWithUseDesignDoc(t *testing.T) {
342327

343328
rawQuery := []byte(`{"selector":{"owner":{"$eq":"jerry"}},"use_index":"_design/testDoc","limit": 10,"skip": 0}`)
344329

345-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
330+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
346331

347332
//Make sure the query did not throw an exception
348333
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
@@ -357,7 +342,7 @@ func TestQueryWithUseDesignDocAndIndexName(t *testing.T) {
357342

358343
rawQuery := []byte(`{"selector":{"owner":{"$eq":"jerry"}},"use_index":["_design/testDoc","testIndexName"],"limit": 10,"skip": 0}`)
359344

360-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
345+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
361346

362347
//Make sure the query did not throw an exception
363348
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")
@@ -372,7 +357,7 @@ func TestQueryWithLargeInteger(t *testing.T) {
372357

373358
rawQuery := []byte(`{"selector":{"$and":[{"size":{"$eq": 1000007}}]}}`)
374359

375-
wrappedQuery, err := ApplyQueryWrapper("ns1", string(rawQuery), 10000, 0)
360+
wrappedQuery, err := ApplyQueryWrapper(string(rawQuery), 10000, 0)
376361

377362
//Make sure the query did not throw an exception
378363
testutil.AssertNoError(t, err, "Unexpected error thrown when for query JSON")

core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb.go

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,7 @@ func (vdb *VersionedDB) ExecuteQuery(namespace, query string) (statedb.ResultsIt
395395
// Get the querylimit from core.yaml
396396
queryLimit := ledgerconfig.GetQueryLimit()
397397

398-
// TODO: Remove namespace from wrapper query
399-
queryString, err := ApplyQueryWrapper(namespace, query, queryLimit, 0)
398+
queryString, err := ApplyQueryWrapper(query, queryLimit, 0)
400399
if err != nil {
401400
logger.Debugf("Error calling ApplyQueryWrapper(): %s\n", err.Error())
402401
return nil, err
@@ -565,15 +564,13 @@ func (vdb *VersionedDB) processUpdateBatch(updateBatch *statedb.UpdateBatch, mis
565564
if isDelete {
566565
// this is a deleted record. Set the _deleted property to true
567566
//couchDoc.JSONValue = createCouchdbDocJSON(string(compositeKey), revision, nil, ns, vv.Version, true)
568-
//TODO: Remove ns/chaincodeID from json doc
569-
couchDoc.JSONValue = createCouchdbDocJSON(key, revision, nil, ns, vv.Version, true)
567+
couchDoc.JSONValue = createCouchdbDocJSON(key, revision, nil, vv.Version, true)
570568

571569
} else {
572570

573571
if couchdb.IsJSON(string(vv.Value)) {
574572
// Handle as json
575-
//TODO: Remove ns from json doc
576-
couchDoc.JSONValue = createCouchdbDocJSON(key, revision, vv.Value, ns, vv.Version, false)
573+
couchDoc.JSONValue = createCouchdbDocJSON(key, revision, vv.Value, vv.Version, false)
577574

578575
} else { // if value is not json, handle as a couchdb attachment
579576

@@ -584,8 +581,7 @@ func (vdb *VersionedDB) processUpdateBatch(updateBatch *statedb.UpdateBatch, mis
584581
attachments := append([]*couchdb.AttachmentInfo{}, attachment)
585582

586583
couchDoc.Attachments = attachments
587-
//TODO: Remove ns from json doc
588-
couchDoc.JSONValue = createCouchdbDocJSON(key, revision, nil, ns, vv.Version, false)
584+
couchDoc.JSONValue = createCouchdbDocJSON(key, revision, nil, vv.Version, false)
589585

590586
}
591587
}
@@ -835,11 +831,10 @@ func (vdb *VersionedDB) ClearCachedVersions() {
835831
// _id - couchdb document ID, need for all couchdb batch operations
836832
// _rev - couchdb document revision, needed for updating or deleting existing documents
837833
// _deleted - flag using in batch operations for deleting a couchdb document
838-
// chaincodeID - chain code ID, added to header, used to scope couchdb queries
839834
// version - version, added to header, used for state validation
840835
// data wrapper - JSON from the chaincode goes here
841836
// The return value is the CouchDoc.JSONValue with the header fields populated
842-
func createCouchdbDocJSON(id, revision string, value []byte, chaincodeID string, version *version.Height, deleted bool) []byte {
837+
func createCouchdbDocJSON(id, revision string, value []byte, version *version.Height, deleted bool) []byte {
843838

844839
// create a version mapping
845840
jsonMap := map[string]interface{}{"version": fmt.Sprintf("%v:%v", version.BlockNum, version.TxNum)}
@@ -858,10 +853,6 @@ func createCouchdbDocJSON(id, revision string, value []byte, chaincodeID string,
858853

859854
} else {
860855

861-
// TODO: Remove chaincodeID from header
862-
// add the chaincodeID
863-
jsonMap["chaincodeid"] = chaincodeID
864-
865856
// Add the wrapped data if the value is not null
866857
if value != nil {
867858

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"index":{"fields":["chaincodeid","data.owner"]},"name":"indexOwner","type":"json"}
1+
{"index":{"fields":["data.docType","data.owner"]},"name":"indexOwner","type":"json"}

examples/chaincode/go/marbles02/marbles_chaincode.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,26 +45,24 @@ under the License.
4545
//Inside couchdb docker container
4646
// http://127.0.0.1:5984/
4747

48-
// Index for chaincodeid, docType, owner.
48+
// Index for docType, owner.
4949
// Note that docType and owner fields must be prefixed with the "data" wrapper
50-
// chaincodeid must be added for all queries
5150
//
5251
// Definition for use with Fauxton interface
53-
// {"index":{"fields":["chaincodeid","data.docType","data.owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
52+
// {"index":{"fields":["data.docType","data.owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
5453
//
5554
// example curl definition for use with command line
56-
// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[\"chaincodeid\",\"data.docType\",\"data.owner\"]},\"name\":\"indexOwner\",\"ddoc\":\"indexOwnerDoc\",\"type\":\"json\"}" http://hostname:port/myc1/_index
55+
// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[\"data.docType\",\"data.owner\"]},\"name\":\"indexOwner\",\"ddoc\":\"indexOwnerDoc\",\"type\":\"json\"}" http://hostname:port/myc1/_index
5756
//
5857

59-
// Index for chaincodeid, docType, owner, size (descending order).
58+
// Index for docType, owner, size (descending order).
6059
// Note that docType, owner and size fields must be prefixed with the "data" wrapper
61-
// chaincodeid must be added for all queries
6260
//
6361
// Definition for use with Fauxton interface
64-
// {"index":{"fields":[{"data.size":"desc"},{"chaincodeid":"desc"},{"data.docType":"desc"},{"data.owner":"desc"}]},"ddoc":"indexSizeSortDoc", "name":"indexSizeSortDesc","type":"json"}
62+
// {"index":{"fields":[{"data.size":"desc"},{"data.docType":"desc"},{"data.owner":"desc"}]},"ddoc":"indexSizeSortDoc", "name":"indexSizeSortDesc","type":"json"}
6563
//
6664
// example curl definition for use with command line
67-
// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[{\"data.size\":\"desc\"},{\"chaincodeid\":\"desc\"},{\"data.docType\":\"desc\"},{\"data.owner\":\"desc\"}]},\"ddoc\":\"indexSizeSortDoc\", \"name\":\"indexSizeSortDesc\",\"type\":\"json\"}" http://hostname:port/myc1/_index
65+
// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[{\"data.size\":\"desc\"},{\"data.docType\":\"desc\"},{\"data.owner\":\"desc\"}]},\"ddoc\":\"indexSizeSortDoc\", \"name\":\"indexSizeSortDesc\",\"type\":\"json\"}" http://hostname:port/myc1/_index
6866

6967
// Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database):
7068
// peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}'

0 commit comments

Comments
 (0)