Making multiple entries with the same key name in Hyperledger - hyperledger

I was trying to write a smart contract that would use the same key name(the name of the person whose details I am storing) multiple times and want all of the entries made for that key-name to be output when querying for the name.
Is it possible on to do so on hyperledger? If yes, then how would you write the query function If not could you recommend an alternate method to achieve the same result?
I am new to hyperledger and have no idea how to proceed considering I didnt see any examples of chaincode similar to this.

What you need to do is to encode the value into JSON format and store it marshaled for the given key, for example you can define a struct with a slice, update/append slice each time with new value, marshal to byte array and then save into ledger.
Each update you read the byte array from the ledger unmarshal it back to struct, update with required information and save back with same key.
To retrieve history of changes you can use one of the methods from ChaincodeStubInterface
// Chaincode interface must be implemented by all chaincodes. The fabric runs
// the transactions by calling these functions as specified.
type ChaincodeStubInterface interface {
// Other methods omitted
// GetHistoryForKey returns a history of key values across time.
// For each historic key update, the historic value and associated
// transaction id and timestamp are returned. The timestamp is the
// timestamp provided by the client in the proposal header.
// GetHistoryForKey requires peer configuration
// core.ledger.history.enableHistoryDatabase to be true.
// The query is NOT re-executed during validation phase, phantom reads are
// not detected. That is, other committed transactions may have updated
// the key concurrently, impacting the result set, and this would not be
// detected at validation/commit time. Applications susceptible to this
// should therefore not use GetHistoryForKey as part of transactions that
// update ledger, and should limit use to read-only chaincode operations.
GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)
}

Related

How do maxKeyCount and addPositiveDiagnosisKeys interact?

I'm learning the new Contact Tracing API that Apple is releasing for iOS (in partnership with Google).
I'm not gasping the relationship of the maxKeyCount property on the CTExposureDetectionSession, and its relationship with the addPositiveDiagnosisKeys: completion: method.
What I understand
A CTExposureDetectionSession is the object that allows an app to ask the framework to start trying to match a list of published Diagnosis Keys against the local database of captured Rolling Proximity Identifiers.
The app would start by calling the activateWithCompletion: method on a new session, and then call addPositiveDiagnosisKeys: one or more times, to eventually inform the framework that no more keys are to be added by calling finishedPositiveDiagnosisKeysWithCompletion:.
That last call will also indicate the block to run upon detection completion, which will be called with a CTExposureDetectionSummary object informing the amount of Diagnosis Keys that the device has been exposed to.
What I do not understand
The maxKeyCount property doc says:
This property contains the maximum number of keys to provide to this API at once. This property’s value updates after each operation complete and before the completion handler is invoked. Use this property to throttle key downloads to avoid excessive buffering of keys in memory.
But the addPositiveDiagnosisKeys: method says:
Asynchronously adds the specified keys to the session to allow them to be checked for exposure. Each call to this method must include more keys than specified by the current value of <maxKeyCount>.
maxKeyCount seems to be a maximum, but the addPositiveDiagnosisKeys: requires me to call it with more keys than the maximum.
Am I expected to call the method with a superlist of the previously sent list? That doesn't seem to fit well with the "avoid excessive buffering of keys in memory" part - if I have to use an ever-growing list of keys.
And what does the This property’s value updates after each operation complete part?
The documentation of maxKeyCount is missing a not.
The Android Contact Tracing API documentation has an analogous interface:
/**
* Provides a list of diagnosis keys for contact checking. The keys are to be
* provided by a centralized service (e.g. synced from the server).
*
* When invoked after the requestProvideDiagnosisKeys callback, this triggers a * recalculation of contact status which can be obtained via hasContact()
* after the calculation has finished. *
* Should be called with a maximum of N keys at a time. */
Task<Status> provideDiagnosisKeys(List<DailyTracingKey> keys);
/**
* The maximum number of keys to pass into provideDiagnosisKeys at any given * time.
*/
int getMaxDiagnosisKeys();
As Paulw11 suggested in a comment, the maxKeyCount property seems to be a value intended for reading that stats how many Diagnosis Keys are to be sent to the API in a single call for the matching to be performed.
Callers should re-check the value before each call, since it may get updated after each call.
The fixed documentation of addPositiveDiagnosisKeys: should, then, read:
Each call to this method must NOT include more keys than specified by the current value of <maxKeyCount>.

How do I filter Purchase Order query in QBXML to only return records that are not fully received?

When doing a PurchaseOrderQuery in QBXML I am trying to get Quickbooks to only return purchase orders that are not yet processed (i.e. "IsFullyReceived" == false). The response object contains the IsFullyReceived flag, but the query object doesn't seem to have a filter for it??
This means I have to get every single Purchase Order whether or not it's received, then do the filtering logic in my application - which slows down Web Connector transactions.
Any ideas?
Thanks!
You can't.
The response object contains the IsFullyReceived flag, but the query object doesn't seem to have a filter for it??
Correct, there is no filter for it.
You can see this in the docs:
https://developer-static.intuit.com/qbSDK-current/Common/newOSR/index.html
This means I have to get every single Purchase Order whether or not it's received, then do the filtering logic in my application - which slows down Web Connector transactions.
Yep, probably.
Any ideas?
Try querying for only Purchase Orders changed or modified (ModifiedDateRangeFilter) since the last time you synced.
Or, instead of pulling every single PO, keep track of a list of POs that you think may not have been received yet, and then only query for those specific POs based on RefNumber.
Or, watch the ItemReceipt and BillPayment objects, and use that to implement logic about which POs may have been recently filled, since BillPayment andItemReceipt` objects should get created as the PO is fulfilled/received.

NSFetchRequest with resultType set to NSDictionaryResultType and saving of changed objects

Based on some limited testing, I see that if I
Execute a Fetch request with result type = NSDictionaryResultType
Do some manipulations on the returned values
Store back the MOC on which Fetch request was executed
the changes in step 2 are not written back to the persistent store because I am changing a dictionary and not a "managed object". Is that a correct understanding?
Most likely you are abusing the dictionary result type. Unlike in conventional database programming, you are not wasting valuable memory resources when fetching the entire objects rather than just one selected attributes, due to an under-the-hood mechanism called "faulting".
Try fetching with managed object result type (default) and you can very easily manipulate your objects and save them back to Core Data. You would not need to do an additional fetch just to get the object you want to change.
Consider dictionaries only in special situations with huge data volumes, difficult relational grouping logic, etc., which make it absolutely necessary.
(That being said, it is unlikely that it is ever absolutely necessary. I have yet to encounter a case where the necessity of dictionaries for fetches was not an indirect result of flawed data model design.)
Yes, kind of, you can't store a dictionary back into the context directly so you can't save any updates that way.
If you get a dictionary object then you need to include in it the associated managed object id (if it isn't aggregated) or do another fetch to get the object(s) to update.

Is HKMetadataKeyWasUserEntered broken? I keep getting nil when there is data in the health app

I'm trying to grab data from the Health App. Specifically data that the user did not enter in themselves. For instance, I have an iPhone 6+ that logs the amount of steps that I take. There is also an option to add the data manually; If you add the data manually, the health app marks the data as "user added".
Here's what's confusing me. Let's say I added a step count of 22. When I query the data using HKStatisticsQuery with a predicate of
HKQuery.predicateForObjectsWithMetadataKey(HKMetadataKeyWasUserEntered, allowedValues: [true])
I get the correct result of 22 steps, since I set the allowedValues to true and that I added this myself. However, when I try to set allowedValues to false, I get no results
HKQuery.predicateForObjectsWithMetadataKey(HKMetadataKeyWasUserEntered, allowedValues: [false])
I do indeed have the step data in the health app, but it returned no results.
Check for the below possible areas to fix it:
did you authorized your application to access Steps data from HealthKit?
If your quering for steps count from your application without authorizing with HealthKit, then HealthKit will not return any exception it will simply returns the steps count which was entered from your application only if available, otherwise returns nil.
Before going to query health data, check for the authorization status for steps count using authorizationStatusForType: method available with HKHealthStore class.
Update 1:
My observations on wasUserEntered key is:
If user entering steps data from HEALTH app, respective HKQuantitySample stores metadata dictionary along with HKWasUserEntered key as TRUE automatically.
If user entering steps data from other than Apple's HEALTH app, respective health/fitness device or our application should send metadata dictionary with key HKWasUserEntered along with value as either TRUE/FALSE. Otherwise, the metadata property will contain nil object. Hence, Apple is not applying predicate(predicate contains metadata key) on the data which don't have metadata with it.
For debugging this metadata, try to print your HKQuantitySampleObject.metadata
Apple's implementation on metadata Vs NSPredicate:
If Health data observed from Health/fitness devices, HealthKit is not adding the metadata dictionary to the respective health record.
In case of Health applications other than Apple's Health app, the developer should manually add the metadata dictionary for his record of health data.
If there is no metadata for a specific health record and NSPredicate have a constraint on metadata then, HealthKit completely omitting to validate such records.
Finally,
It is advised to use
(instancetype)quantitySampleWithType:(HKQuantityType *)quantityType
quantity:(HKQuantity *)quantity
startDate:(NSDate *)startDate
endDate:(NSDate *)endDate
metadata:(NSDictionary *)metadata;
instead of
+ (instancetype)quantitySampleWithType:(HKQuantityType *)quantityType
quantity:(HKQuantity *)quantity
startDate:(NSDate *)startDate
endDate:(NSDate *)endDate;
to add metadata.
Reporting Apple regarding this bug that, predicate(which contains metadata key) should be applied on all the data irrespective of checking for metadata exists or not.
It's been a while and you have probably solved this by now, but I think it is worth posting here in case someone else comes across the same issue.
Like Bhanu mentioned, data created by Apple themselves doesn't seem to have the HKWasUserEntered entry as part of its metadata.
But Apple never claims to do it anyway in their docs, so the proper query would be one that filtered out items with HKWasUserEntered == true if that key was set, but also gave back everything else that had no metadata associated.
The ideia is that metadata is a Dictionary, and that type returns nil if a key does not exist. So there are three possible scenarios:
HKMetadataKeyWasUserEntered == nil
HKMetadataKeyWasUserEntered == false
HKMetadataKeyWasUserEntered == true
Out of those, you just want to filter out the last one, since that explicitly tells you that data was entered but the user.
This can be done using the + predicateForObjectsWithMetadataKey:operatorType:value: convenience method on HKQuery, like this:
HKQuery.predicateForObjects(withMetadataKey: HKMetadataKeyWasUserEntered, operatorType: .notEqualTo, value: true)
But of course, your initial question was: "Is HKMetadataKeyWasUserEntered broken?". And I don't believe it is, since, like mentioned, Apple never claims to write that key for their own values. :)

Which records will be downloaded when CKFetchRecordChangesOperation will called with nil token?

Will CKFetchRecordChangesOperation retrieve all records from container?
I hoped it will download all my records, since I added many to different record types, but I get no one. I've initialised it with nil token.
reference says: A CKFetchRecordChangesOperation object reports on the changed and deleted records in the specified record zone. Use this type of operation object to optimize fetch operations for locally managed sets of records. Specifically, use it when you maintain a local cache of your record data and need to synchronize that cache periodically with the server.
I even runned CKFetchRecordChangesOperation from different device to exclude the case only changes performed on other devices is returned.
CKFetchRecordChangesOperation has nothing to do with CKSubscription. Instead it will just return all the changes to all recordTypes.
The documentation says this about the change token:
The change token from a previous fetch operation. This is the token
passed to your fetchRecordChangesCompletionBlock handler during a
previous fetch operation. Use this token to limit the returned data to
only those changes that have occurred since you last made the same
fetch request. If you specify nil for this parameter, the operation
object fetches all records and their contents.
So you will just get all the records.

Resources