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!
Related
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
I have a single collection into which I am inserting documents of different types. I use the type parameter to distinguish between different datatypes in the collection. When I am inserting a document, I have created an Id field for every document, but Cosmosdb has a built-in id field.
How can I insert a new document and retrieve the id of the created Document all in one query?
The CreateDocumentAsync method returns the created document so you should be able to get the document id.
Document created = await client.CreateDocumentAsync(collectionLink, order);
I think you just need to .getResource() method to get the create document obj.
Please refer to the java code:
DocumentClient documentClient = new DocumentClient(END_POINT,
MASTER_KEY, ConnectionPolicy.GetDefault(),
ConsistencyLevel.Session);
Document document = new Document();
document.set("name","aaa");
document = documentClient.createDocument("dbs/db/colls/coll",document,null,false).getResource();
System.out.println(document.toString());
//then do your business logic with the document.....
C# code:
Parent p = new Parent
{
FamilyName = "Andersen.1",
FirstName = "Andersen",
};
Document doc = client.CreateDocumentAsync("dbs/db/colls/coll",p,null).Result.Resource;
Console.WriteLine(doc);
Hope it helps you.
Sure, you could always fetch the id from creation method response in your favorite API as already shown in other answers. You may have reasons why you want to delegate key-assigning to DocumentDB, but to be frank, I don't see any good ones.
If inserted document would have no id set DocumentDB would generate a GUID for you. There wouldn't be any notable difference compared to simply generating a new GUID yourself and assign it into id-field before save. Self-assigning the identity would let you simplify your code a bit and also let you use the identity not only after persisting but also BEFORE. Which could simplify a lot of scenarios you may have or run into in future.
Also, note that you don't have to use GUIDs as as id and could use any unique value you already have. Since you mentioned you have and Id field (which by name, I assume to be a primary key) then you should consider reusing this instead introducing another set of keys.
Self-assigned non-Guid key is usually a better choice since it can be designed to match your data and application needs better than a GUID. For example, in addition to being just unique, it may also be a natural key, narrower, human-readable, ordered, etc.
I would like to create work order using escalation once the asset is moved to some other location (like REPAIR) using move/modify. I do understand that we can trigger CREATEWO however I am not sure on how to set the values on some fields in work order like worktype, workact , etc. Also I am unable to pick the correct record which has performed move modify ( unable to fetch the exact record using ASSETTRANS table).
Let me know if anyone has done this before, thanks in advance!
It sounds like you have an Escalation calling an Action that calls the AppAction CREATEWO. Assuming that's correct..
First, create a Relationship in DB Config between the ASSET object and WORKORDER that will find the most recent work order against this asset. You can look at the NEWWORKORDER relationships on WORKORDER and TICKET as an example. For reference, I will assume you name this relationship MYNEWWORKORDER.
Next, create some Actions against the ASSET object that use MYNEWWORKORDER.<ATTRIBUTENAME> in the Parameter/Attribute field, where <ATTRIBUTENAME> is the name of the attribute (e.g. WORKTYPE) you want to supply a value for in the Value field.
Once that is done, create an Action of type Action Group where CREATEWO is the first member and the Actions you just made are the succeeding members.
Finally, update the Escalation to call your new Action Group instead of the numbered one that the Escalation application created for you.
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.
According to the help pop up:
ID
This field's value represents the script ID, used to identify this
record for scripting purposes. It is a text field.
Internal ID
This field's value is a read-only system-generated unique identifier.
It is an integer field.
Both fields seem to uniquely identity a record type.
One is a string, one a integer.
The string ID is used for searches and
loading of records, but I've also seen Internal ID used when
referring to a record type from a lists point of view.
Can anyone provide the reasoning behind having two identifiers and when to use one versus the other when scripting?
The major difference is that you (as the creator of a custom record or script) are in complete control of the text ID. You can establish patterns and best practices for defining these IDs, and it will make it very easy for developers to identify record types just by looking at the string ID. You have no control over the numeric ID. When looking at code, it is much easier for me to determine what records I am referring to if it looks like:
nlapiSearchRecord('customrecord_product', null, filters, columns);
nlapiResolveURL('SUITELET', 'customscript_sl_orderservice', 'customdeploy_sl_orderservice')
as opposed to looking at:
nlapiSearchRecord(118, null, filters, columns);
nlapiResolveURL('SUITELET', 13, 1)
I'm not even sure the second nlapiSearchRecord actually works, but I know that nlapiResolveURL can be written that way.
That said, if you simply let NetSuite generate the text ID, you'll end up with generic IDs like customrecord1, which I find no more useful than the numeric ID. It is a good practice to explicitly specify your own IDs.
Furthermore, the numeric ID can vary between environments (e.g. Sandbox could be different than Production, until a subsequent refresh occurs). If you are following good migration practices, then the text ID should never vary between environments, so your code would not have to make any kind of decision on which ID to use based on environment.
Rarely have I found myself referencing any record, whether native or custom, by its numeric ID; scripts are always using the text ID to reference a record type.