i need help with the getQueryResult() function in hyperledger fabric.
I know that i can use it this way:
String queryHash;
QueryResultsIterator<KeyValue> results = stub.getQueryResult("{\"selector\":{\"hash\":\"" + queryHash + "\"}}");
to run a query that searches each asset for those with the hash parameter set to the queryHash string.
At the moment, however, I have 3 different type of assets and I would like to understand how to set the search on only one of them.
Let me explain. Let us suppose that I have 3 different types of assets. For example, an asset called a car, with its attributes (id, name, model, etc.), an asset called a truck, also with its attributes, and another called an aeroplane, also with its attributes.
Let's say I want to make a query that searches for all the cars by make, but without including trucks and planes.
How can I indicate in the query that I am referring only to that type of asset?
Thanks
Why querying on a single object?
I don't know about your chaincode models, but supposing you have some kind of ID, it would be something like:
String id;
String queryHash;
// ...
QueryResultsIterator<KeyValue> results = stub.getQueryResult("{\"selector\":{\"id\":\"" + id + "\"" + ", " + "\"hash\":\"" + queryHash + "\" }}");
If you have access to its CouchDB key, you can simply get the object and check the hash when deserialized:
String couchdbKey;
// ...
byte[] ba = stub.getState(couchdbKey);
// Deserialize ba and check hash
EDIT
I think you should refactor your models. I usually develop chaincodes in Go, but in Java it could be something like (check the code, it is written on the fly):
public abstract class Asset {
#Property()
private String doctype;
#Property()
private String id;
protected Asset(String doctype) {
this.doctype = doctype;
}
public String getDoctype() {
return doctype;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
// ...
}
#DataType()
public class Car extends Asset {
public static final String DOCTYPE = "car";
public Car() {
super(Car.DOCTYPE);
}
// ...
}
Then, you can query on doctype for each model. And you should preferably create an index for doctype.
Related
I'm trying to figure out how can i store Long info about a Discord user in an array.
Tommy on discord type: ;create
then
Mike on discord type : ;create
public class Create extends ListenerAdapter {
public void onMessageReceived(MessageReceivedEvent event) {
if (!event.isFromGuild()) return;
String[] messageSent = event.getMessage().getContentRaw().split(" "); //for further code
String name = event.getMember().getUser().getName();
long idLong = event.getMember().getUser().getIdLong();
String idString = event.getMember().getUser().getId(); //not for Stackoverflow question
long base = 1L; //everyone start with 1 (L is because we are using Long version of int value)
if (messageSent[0].equalsIgnoreCase(";Create")) {
ArrayList<Long> dcbase = new ArrayList<>(); //Long is used to store getIdLong value
dcbase.add(idLong); //
dcbase.add(base); // 1L is default value
event.getChannel().sendMessage("Here is the array "+ dcbase).queue();}}
Now the problem is if i want my ArrayList to be for many user I would need an ArrayList of ArrayList. Arraylist<ArrayList<Long>>
But to search through them I would like to do search using the IdLong value.
I tried to replace dcbase as idLong but its already defined.
Is there any way i can do that?
Because what i want to do next is have a method that goes to the idLong of Tommy and pull out the [1] of the Tommy ArrayList.
I plan to store the info to a file that way and will have longer Arrays:
177877878787 1 0 0 //Tommy IdLong, base Long, stuff i'll add, stuff i'll add
121244777778 1 //Mike IdLong, base Long
//New line for new member.
Since I don't know on which line the required IdLong will be stored in the file, i need a reference to search it.
I am self-thaught, I hope I am clear enough.
You want a Map. The key is the user id (as a long) and the value is your number:
private final Map<Long, Long> map = new HashMap<>();
#Override
public void onMessageReceived(MessageReceivedEvent event) {
...
map.put(id, base);
...
}
You can then simply access the value by using map.get(id). Instead of using lists, I would recommend using proper objects with defined fields for whatever data you want to store.
For the case of persistence, instead of just writing your data to some file, use a relational database like PostgreSQL or SQLite. This way you can easily update them at runtime without having to read/write the entire map every time you want to access it.
A very helpful thing to use for this is the Java Persistence API (JPA).
#Entity
#Table
public class UserInfo {
#Id
private long id;
private long base;
public UserInfo(long id, long base) {
this.id = id;
this.base = base;
}
public void setId(long id) {
this.id = id;
}
public long getId() { return this.id; }
public void setBase(long base) {
this.base = base;
}
public long getBase() { return this.base; }
}
I have a nested POJO structure defined something like this,
public class Employee {
private String id;
private Personal personal;
private Official official;
}
public class Personal {
private String fName;
private String lName;
private String address;
}
public class Official {
private boolean active;
private Salary salary;
}
public class Salary {
private double hourly;
private double monthly;
private double yearly;
}
I get updates from a service with dot annotaion on what value changed, for ex,
id change --> id=100
address change --> personal.address=123 Main Street
hourly salary change --> official.salary.hourly=100
This POJO structure could be 3-4 level deeps. I need to look for this incoming change value and update the corresponding value in POJO. What's the best way of doing it?
If you would like to create Java objects that allows you to edit fields. You can specify your object fields with the public/default/protected access modifiers. This will enable you to get and set fields such as personal.address or official.salary.hours
This approach is typically frowned upon as the object is no longer encapsulated and any calling methods are welcome to manipulate the object. If these fields are not encapsulated with getters and setters, your object is no longer a POJO.
public provides access from any anywhere.
default provides access from any package
protected provides access from package or subclass.
public class Employee {
public String id;
public Personal personal;
public Official official;
}
public class Personal {
public String fName;
public String lName;
public String address;
}
Here's a quick approach using reflection to set fields dynamically. It surely isn't and can't be clean. If I were you, I would use a scripting engine for that (assuming it's safe to do so).
private static void setValueAt(Object target, String path, String value)
throws Exception {
String[] fields = path.split("\\.");
if (fields.length > 1) {
setValueAt(readField(target, fields[0]),
path.substring(path.indexOf('.') + 1), value);
return;
}
Field f = target.getClass()
.getDeclaredField(path);
f.setAccessible(true);
f.set(target, parse(value, f.getType())); // cast or convert value first
}
//Example code for converting strings to primitives
private static Object parse(String value, Class<?> type) {
if (String.class.equals(type)) {
return value;
} else if (double.class.equals(type) || Double.class.equals(type)) {
return Long.parseLong(value);
} else if (boolean.class.equals(type) || Boolean.class.equals(type)) {
return Boolean.valueOf(value);
}
return value;// ?
}
private static Object readField(Object from, String field) throws Exception {
Field f = from.getClass()
.getDeclaredField(field);
f.setAccessible(true);
return f.get(from);
}
Just be aware that there's a lot to improve in this code (exception handling, null checks, etc.), although it seems to achieve what you're looking for (split your input on = to call setValueAt()):
Employee e = new Employee();
e.setOfficial(new Official());
e.setPersonal(new Personal());
e.getOfficial().setSalary(new Salary());
ObjectMapper mapper = new ObjectMapper();
setValueAt(e, "id", "123");
// {"id":"123","personal":{},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "personal.address", "123 Main Street");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "official.salary.hourly", "100");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":100.0,"monthly":0.0,"yearly":0.0}}}
This is really frustrating. I would like to print out the name of the game object alongside the comment objects related to them. The reviews/replies are called by reference of the the object. I can tell the compiler knows the reference because it groups reviews and replies by game.
I want it like this:
Reviews for The Witcher 3 --- the part I want, the rest is easy.
Rev1/ User ID: u1; Name: JD; "This game is timeless!"
Rep1/ User ID: u2; Name: Boss; "Really? You run around in imaginary fields hunting for imaginary creatures...lame."
Rep2/ User ID: u1; Name: JD; "Blah, blah, something."
Other games ect...
Reviews group perfect for game type and replies group perfectly under the review. But I can't find a way to show the game the reviews are for. Is there a way?
Any help would be great.
review and reply methods are called like this:
game1.addReviews(review1);
review1.addReply(reply1);
reply1.addReply(reply2);
....
public class Comment {
protected List<Comment> reply = new ArrayList<Comment>();
private User user;
private String usrComment;
public Comment() {
}
public void addReply(Comment r) {
this.reply.add(r);
}
#Override
public String toString() {
return this.user.getUsr() + '"' + this.usrComment + '"';
}
...
public abstract class Content {
protected List<Comment> Review = new ArrayList<Comment>();
private String ID;
private String Application_Name;
// constructor to take ID, name and price of app
public Content(String iD, String application_Name, double price) {
super();
ID = iD;
Application_Name = application_Name;
Price = price;
}
public void addReviews(Comment a) {
this.Review.add(a);
}
}
...
public class Game extends Content {
private boolean isMultiPlayer;
private OS o;
private double Price = 0;
public Game(String iD, String application_Name, double price, boolean isMultiPlayer, OS o) {
super(iD, application_Name, price);
this.isMultiPlayer = isMultiPlayer;
this.o = o;
}
}
This was silly. The object (game) is the object calling the method and passing another object as an argument. So any method or value related to the calling game object can be accessed within the method called. I was using two advanced loops and recursion, so I may have confused myself a little.
I have a class called Doctor, and a class Patient that extends it. In my application, a Doctor logs in with a username and password and he registers a bunch of Patients.
The Doctor ID has a hashcode() method that I know works (auto-generated by Eclipse and was tested before as generating unique hashcodes based on usernames), as does a Patient.
I have a variable called patientdID and patientduserName, and dID and duserName (the doctor's ones). and getters and setters for both the doctor and patient.
When a patient is registered, I want to generate a file of patient fields which include the doctor who registered the patient, and the patient registered, via the toString() method of Patient. However, right now, the patientdID is not set as the dID, and the patientdID always stays at 31 (it is not really the true hashcode of the doctor).
When a patient is registered, the following code is called (relevant parts inserted):
patient = new Patient();
doctor = new Doctor();
patient.setpatientdID(doctor.getdID());
patient.setpatientdUserName(usernameField.getText());
The getters for these fields for the patient are:
public void setpID(int pID) {
this.pID = pID;
}
public int getpatientdID() {
return patientdID;
}
public void setpatientdID(int patientdID) {
this.patientdID = patientdID;
}
public String getpatientdUserName() {
return patientduserName;
}
And for Doctor are:
public int getdID() {
return dID;
}
public void setdID(int dID) {
this.dID = dID;
}
public String getDuserName() {
return duserName;
}
public void setDuserName(String duserName) {
this.duserName = duserName;
}
And constructors for Doctor are:
public Doctor() {
this.dID = this.hashCode();
this.duserName = duserName;
this.dpassWord = dpassWord;
}
And for Patient are:
public Patient() {
super();
this.pFirstName = pFirstName;
this.pLastName = pLastName;
this.pDob = pDob;
this.pAddress = pAddress;
this.pPhoneNumber = pPhoneNumber;
this.pBillingCycle = pBillingCycle;
this.pMedicalCondition = pMedicalCondition;
this.pComments = pComments;
}
Finally, the toString() method of patient is:
public String toString() {
return patientdID+","+patientduserName+","+this.hashCode() + "," + pFirstName + "," + pLastName + "," + pDob
+ "," + pAddress + "," + pPhoneNumber + "," + pBillingCycle
+ "," + pMedicalCondition + "," + pComments;
}
I have tinkered and hacked through this to understand but would prefer an answer which told me how to structure my code, given my objective, and what I should be doing e.g. calling super somewhere etc.
First and foremost -- the Patient class should NOT extend Doctor. Period. This is not and never can be an is-a relationship but instead is a has-a relationship: a patient has a doctor (or more than one). So give Patient a Doctor field, if they have one doctor or a List<Doctor> if they have multiple doctors, and fill the field as needed. Then you can extract information from the field as needed.
As side recommendations:
I would not use hashCode for ID's. Also I would avoid using ints or any other numeric type for this, since an ID is not something that you would do numeric operations on, such as adding or subtracting. I'd use a String instead.
Your parameterless constructors that are setting fields to themselves are useless. In this situation, this, this.pFirstName = pFirstName; will just set pFirstName to whatever the class initially defined it as, perhap null even. Use parameters when you need to.
OK to use inheritance to give Doctor and Patient a shared base class, say called Person. This can have a name field, an id field, and any other shared fields, with the appropriate constructors.
For example, something like:
// a base class that abstracts what is shared by Doctor and Patient
public class Person {
private String id;
private String name;
// .... etc
public Person(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
public class Doctor extends Person {
private List<Patient> patients = new ArrayList<>();
public Doctor(String id, String name /* add any additional params here*/) {
super(id, name);
// ... set fields here
}
public boolean addPatient(Patient p) {
return patients.add(p);
}
}
public class Patient extends Person {
private Doctor doctor;
public Patient(String id, String name, Doctor doctor /* add any additional params here*/) {
super(id, name);
this.doctor = doctor;
// ... set additional fields here
}
// you can get the Doctor's id from its object
public Doctor getDoctor() {
return doctor;
}
}
I have figured this out using hashcodes, but appreciate the answer above.
The username needed to be set before a doctor hashcode was created (as the hashcode relies on it). So, I needed:
doctor.setDuserName(usernameField.getText());
patient.setpatientdID(doctor.hashCode());
I also removed references to super() in the constructor for a patient but I don't think this makes a difference, as I am not overriding the doctor IDs.
I agree with you on the inheritance point. My patientdID and patientdUserName variables within Patient are similar to when you say "give the patient a Doctor field".
I'm implementing the "auto-increment" id using strategy described here:
http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/
Basically the value of the seqId field is set by calling an utility function that updates the counter on an auxiliary collection and returns the incremented value. Sounds great.
My issue is in mapping this to be used with Morphia. The tutorial suggests performing the insert (such as in the shell) like so:
db.users.insert(
{
seqId: getNextSequence("userid"),
name: "Sarah C."
}
I'm basically looking to do something like setting the POJO seqId field to something that Morphia will translate into an insert like the one above when I invoke save().
My POJO looks like this:
#Entity
public class User {
#Id
private Long id;
// THIS IS THE FIELD I WANT TO AUTO-INCREMENT
private Long seqId;
private String name;
...
}
The question is: How to make Morphia set the value of a field as the value returned by a function call?
I looked into using the #PrePresist annotation to perform this function call and getting the value, then setting it in the +_id field. That has several drawbacks such as making multiple calls to MongoDB instead of just one, and also the fact that my model objects don't have a reference to the datastore and I'd rather not mix up the concerns.
Is this possible? Any suggestions?
I'm on MongoDB 2.6.6 using the latest Java drivers.
Thanks!
PS: I'm aware that auto-increment is not recommended in large environments. I need it anyways for this specific scenario.
I'll describe the solution that's working for us quite well. Note that this supports auto increments on the class level and a subset of it — so you can count users or admin-users (user with an admin enum or whatever).
This contains the current value for each auto increment field, it's basically a reference:
#Entity(noClassnameStored = true)
public class AutoIncrementEntity {
#Id
protected String key;
protected Long value = 1L;
protected AutoIncrementEntity() {
super();
}
/**
* Set the key name — class or class with some other attribute(s).
*/
public AutoIncrementEntity(final String key) {
this.key = key;
}
/**
* Set the key name and initialize the value so it won't start at 1.
*/
public AutoIncrementEntity(final String key, final Long startValue) {
this(key);
value = startValue;
}
public Long getValue() {
return value;
}
}
In your persistence service, you could use the following to set / create the auto increment automatically:
public <E extends BaseEntity> ObjectId persist(E entity) {
// If it's a user and doesn't yet have an ID, set one; start counting from 1000.
if ((entity instanceof UserEntity) && (((UserEntity) entity).getUserId() == null)) {
((UserEntity) entity).setUserId(
generateAutoIncrement(entity.getClass().getName(), 1000L));
}
// Additionally, set an ID within each user group; start counting from 1.
if ((entity instanceof UserEntity) && (((UserEntity) entity).getRoleId() == null)) {
((UserEntity) entity).setRoleId(
generateAutoIncrement(entity.getClass().getName() + "-" + entity.getRole(), 1L));
}
mongoDataStore.save(entity);
return entity.getId();
}
/**
* Return a unique numeric value for the given key.
* The minimum value, set to 1 if nothing specific is required.
*/
protected long generateAutoIncrement(final String key, final long minimumValue){
// Get the given key from the auto increment entity and try to increment it.
final Query<AutoIncrementEntity> query = mongoDataStore.find(
AutoIncrementEntity.class).field("_id").equal(key);
final UpdateOperations<AutoIncrementEntity> update = mongoDataStore
.createUpdateOperations(AutoIncrementEntity.class).inc("value");
AutoIncrementEntity autoIncrement = mongoDataStore.findAndModify(query, update);
// If none is found, we need to create one for the given key.
if (autoIncrement == null) {
autoIncrement = new AutoIncrementEntity(key, minimumValue);
mongoDataStore.save(autoIncrement);
}
return autoIncrement.getValue();
}
And finally your entity:
#Entity(value = "user", noClassnameStored = true)
public class UserEntity extends BaseEntity {
public static enum Role {
ADMIN, USER,
}
private Role role;
#Indexed(unique = true)
private Long userId;
private Long roleId;
// Role setter and getter
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
}
There's nothing specific going on in the entity. All the logic is handled by the persistence service. I'm not using the #PrePersist, because you'd then need to put the persistence service into the entity, which doesn't sound like a good idea.