I want to anchor some data on the Hyperledger Fabric which should be immutable, so that when I read this value anytime in the future, the value should remain the same.
I think I can modify the stateDB and store that data as a key value pair using stub.PutState
{
"data": "mydata"
}
and note the transaction ID.
However, since the state DB is mutable, I can do something like this instead of doing a stub.GetState
stub.GetHistoryForKey("data")
iterate over and match the transaction ID and then read the value of the key.
However, is there a way to directly read this value from a transaction given that I already have the transaction ID instead of iterating over the history?
Or is there a better way to do this?
You can use QueryBlockByTxnID method or QueryTransaction method(as mentioned by kartik in the comment). But you need to parse or format the data by yourself.
here's the github reference: https://github.com/hyperledger/fabric-sdk-go/blob/87f5eb8a655f3d2588e5d1729b2ecf888e52f4ac/pkg/client/ledger/ledger.go#L277
Related
I am trying to setup a new Cosmos DB and it's asking me to set a partition key. I think I understand the concept where I should select a JSON field that can group my documents efficiently.
Is it possible to configure the collection to use a JSON field that may not exist in every incoming document?
For example:
{
"name" : "Robin",
"DOB" : "01/01/1969",
"scans" : {
"bloodType" : "O"
}
}
{
"name" : "Bill",
"DOB" : "01/01/1969"
}
Can I use /scans.bloodType as the partion key? For documents that don't have a scans JSON field, I still want that data as I can update that document later.
You can, indeed, specify a partition key that might not exist in every document. When you save a document that's missing the property specified by your partition key, it will result in assigning an "undefined" value for its partition key.
In the future, if you wanted to provide a value for the partition key of such a document, you'd have to delete, and then re-add, the document. You cannot modify a property's value when it happens to be the partition key within that document's container (nor can you add the property to an existing document that doesn't explicitly have that property defined, since it's already been assigned the "undefined" value).
See this answer for more details on undefined partition key properties.
Unfortunately you can't do that.
As per the official docs the partition key path (/scans.bloodType) or the partition key value cannot be changed.
Be a property that has a value which does not change. If a property is your partition key, you can't update that property's value.
In terms of solutions, you could either try and find another partition Key property path and ensure there's a value at the time of creation, or maybe use a secondary collection to store your incomplete documents and use the change feed to "move" them to the final collection once all the data becomes available.
Something like blood type wouldn't be a good partition key, assuming it refers to A/B/O types, etc, if there are only a small number of possible values. What you can generally always fall back on is the unique id property of the item, which Cosmos creates automatically. It's fine to have one item per partition, if nothing else is a better candidate. Per docs:
If your container has a property that has a wide range of possible
values, it is likely a great partition key choice. One possible
example of such a property is the item ID. For small read-heavy
containers or write-heavy containers of any size, the item ID is
naturally a great choice for the partition key.
I am working on Azure and I have created a database with Cosmos DB SQL API. After creating a container I see that the primary key is always named "id". Is there any way to create a container with PK with name different than "id"?
Every document has a unique id called id. This cannot be altered. If you don't set a value, it is assigned a GUID.
When using methods such as ReadDocument() (or equivalent, based on the SDK) for direct reads instead of queries, a document's id property must be specified.
Now, as far as partitioning goes, you can choose any property you want to use as the partition key.
And if you have additional domain-specific identifiers (maybe a part number), you can always store those in their own properties as well. In this example though, just remember that, while you can query for documents containing a specific part number, you can only do a direct-read via id. If direct reads will be the majority of your read operations, then it's worth considering the use of id to store such a value.
PK = primary key, by the way ;) It's the "main" key for the record, it is not private :)
And no, as far as I know you cannot change the primary key name. It is always "id". Specifically it must be in lowercase, "Id" is not accepted.
There is a method in a factory newResource.
The third parameter of this method is id. Are there any ways or workarounds to generate id?
There was a similar question if you mean to auto-increment the identifier:
Auto Increment field in Composer
It is not recommended by the devs, because different peers may have calculated the IDs at the same time for different new assets/participants and disagree. Disagreements would force all records to roll back.
Source: https://github.com/hyperledger/composer/issues/2931
You control what the id is generated as (deterministically) when you create the new Resource in the Resource registry (whether its an AssetRegistry or ParticipantRegistry etc) and depends on the id field type that identifies the asset/participant.
See sample networks for examples. Eg Perishables network:
https://github.com/hyperledger/composer-sample-networks/blob/v0.16.x/packages/perishable-network/lib/logic.js#L133
Here, Grower is created as a Resource using an email id as the identifier of the Resource.
see model here -> https://github.com/hyperledger/composer-sample-networks/blob/v0.16.x/packages/perishable-network/models/perishable.cto
here - the Participant Grower is extended from a generic Business participant that is identified by an email id (as it inherits that field from the supertype).
This is a real problem and the Hyperledger documentation is not clear about which is the right approach.
When you create a new resource the third parameter id is mandatory and the transaction is rejected if it already exists another asset with the same id. So, how to fill the parameter id of newResource?
factory.newResource(ns, type, id)
A solution could be counting the assets of the same type and generating a pseudo-incremental ID. But this should be used only for assets that are kinda unique on the blockchain. You should use this approach if you don't care of the rejection of the transaction by the peers; or maybe if the rejection is wanted behavior, because a deterministic unique id could work like a unique constraint (like in sql). A big flaw of "counting the assets" is the hyperledger query language doesn't do that, so you you have to use getAll method of the AssetRegistry and then get length of the array, which is not scalable for big arrays:
let bananas_registry = await getAssetRegistry("org.exampleblockchain.Banana");
let all_bananas = await bananas_registry.getAll();
let new_banana_id = String(all_bananas.length + 1);
Another way to get unique ID is concatenate ID of parent assets.
But sometimes I also need something like a real random ID (not incremental). I do not understand why the is not the default for the parameter Id.
Anyway, when I will need a real random ID, I will generate a long random string so the risk of collision with other peers will be low. I will let you know!
We want to check if a document already exists in the database with the same fields and values of a new object we are trying to save to prevent duplicated item.
Note: This question is not about updating documents or about duplicated document IDs, we only check the data to prevent saving a new document with the same data of an existing one.
Preferably we'd like to accomplish this with Mango/Cloudant queries and not rely on views.
The idea so far is:
1) Scan the the data that we are trying to save and dynamically create a selector that matches that document's structure. (We can't have the selectors hardcoded because we have types of many documents)
2) Query de DB with for any documents matching that selector to if any document already exists that matches those criteria.
However I wonder about the performance of this approach since many of the selector fields will not be indexed.
I also much rather follow best practices than create something out of the blue, but haven't been able to find any known solutions for this specific scenario.
If you happen to know of any, please share.
Option 1 - Define a meaningful ID for your documents
The ID could be a logical coposition or a computed hash from the values that should be unique
If you want to check if a document ID already exists you can use the HEAD method
HEAD /db/docId
which returns 200-OK if the docId exits on the database.
If you would like to check if you have the same content in the new document and in the previous one, you may use the Validate Document Update Function which allows to compare both documents.
function(newDoc, oldDoc, userCtx, secObj) {
...
}
Option 2 - Use content hash computed outside CouchDB
Before create or update a document a hash should be computed using the values of the attributes that should be unique.
The hash is included in the document in a new attribute i.e. "key_hash"
Create a mango index using the "key_hash" attribute
When a new doc should be inserted, the hash should be computed and find for documents with the same hash value using a mango expression before the doc is inserted.
Option 3 - Compute hash in a View
Define a view which emit the computed hash for each document as key
Couchdb Javascript support does not include hashing functions, this could be difficult to include in a design document.
Use erlang to define the map function, where you can access to the erlang support for hashing.
Before creating a new document you should query the view using a the hash that you need to compute previously.
One solution would be to take Juanjo's and Alexis's comment one step further.
Select the keys you wish to keep unique
Put the values in a string and generate a hash
Set the document's _id to that hash
PUT the document on the database.
check return for failure
If another document already exists on the database with the same _id value, the PUT request will fail.
In reference material for CouchDB and Couchbase it's common guidance to store the type of a document as a parameter within the actual document.
I've got a database, where I have different documents that record certain behaviour by URL. So naturally, I use the URL as the id of the document.
The problem I find is that by using just the key as the document id, I now get clashes between documents of different types. So I have started using the type as the first part of the key like this:
{ doc._id: "rss_entry|http://www.spiegel.de/1234", [...] }
{ doc._id: "page_text|http://www.spiegel.de/1234", [...] }
Now I start to wonder why I've never seen this approach to model type in any of the documentation.
Prefixes are commonly used. In addition to support for scenarios such as yours, prefixing allows one to perform logical range queries against views. There is use of this technique in the modeling examples, but perhaps the concept is not described in as much detail as you are expecting. In the section http://docs.couchbase.com/couchbase-devguide-2.5/#modeling-documents, the documents are keyed as beer_NNNN and brewery_NNNN. Also, the section http://docs.couchbase.com/couchbase-devguide-2.5/#using-reference-documents-for-lookups goes a bit deeper into this technique. There is a counter document named user::count and then each user is keyed as user::NNNN. Additionally, there are documents in the example that are keyed as fb::NNNN for a Facebook ID, email::XXX#YYYY.com for a user's email address, etc.