I'd like to use a unique string per collection to id a doc. I'm using Scala and Casbah but can also use Java if needed.
I know I should use Casbah collection.createIndex but I don't understand the scaladocs.
If my case class is :
case class GroupParams (
_id: String,
//groupId: String,
testPeriodStart: DateTime, // ISO8601 date
variants: Seq[String], //["17","18"]
testPeriodEnd: Option[DateTime])
and I will always use the _id to reference a particular document (no need for _id: ObjectId).
I don't care about sorting/ordering since these will only be accessed as individual docs, never cursored through. There seems no reason to have the overhead of another index on the default _id: ObjectId.
How to I create the index on the collection with _id: String using Casbah? If I should create a new index and leave the default alone can you show how to do this?
Mongo automatically creates index for _id field for all types (ObjectId, String or whatever you want) - mongo indexes
Mongo automatically generate a _id to your index in the collection,
if you want to insert String to the _id you can convert a String to objectId like this : ObjectId.Parse(myString))
See more in the MongoDB API
Related
I created an entity (Model or Data class) in a Spring-Boot (Kotlin) project which contains a field with the type Arraylist but when I send an array data in JSON format from Postman, the Array gets stored in the database as a long random string.
When I try to retrieve the data from the database I get the actual array, perfectly formated.
My question is why is an ArrayList stored in an H2 database like this???
Evaluation.kt
#Entity
data class Evaluation (
#Id val id : String,
val timeStamp : Long,
val symptoms : ArrayList<String>,
val travelHistory : Boolean,
val contactWithCovidPatient : Boolean,
val evaluatedBy : String,
var evaluationPercentage : String? = null,
#ManyToOne var user: User? = null
)
EvaluationController.kt
#RestController
class EvaluationController (val evaluationService: IEvaluationService) {
#PostMapping("evaluate/{userId}")
fun evaluateUser(#PathVariable userId : String, #RequestBody evaluation: Evaluation) : ResponseEntity<Evaluation> =
ResponseEntity.ok().body(evaluationService.addEvaluation(evaluation, userId))
}
Request Body JSON
{
"id":"e_01",
"timeStamp":"123456789",
"pinCode":"123457",
"travelHistory":true,
"contactWithCovidPatient":true,
"evaluatedBy":"u_01",
"symptoms": ["Fever","Cough"]
}
Response JSON
{
"id": "e_01",
"timeStamp": 123456789,
"symptoms": [
"Fever",
"Cough"
],
"travelHistory": true,
"contactWithCovidPatient": true,
"evaluatedBy": "u_01",
"evaluationPercentage": "95",
"user": {
"id": "u_01",
"name": "abc01",
"phoneNumber": "9876543210",
"pinCode": "123457",
"covidResult": "Positive"
}
}
H2 Database Table
This is a hex string representing the serialized ArrayList object. See Serializable Objects for details about object serialization in Java.
Running the following code yields the same result:
List<String> symptoms = new ArrayList<>(Arrays.asList("Fever", "Cough"));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(symptoms);
byte[] serializedObject = byteArrayOutputStream.toByteArray();
String hex = Hex.encodeHexString(serializedObject); // Apache Commons Codec
System.out.println(hex);
aced0005737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000027704000000027400054665766572740005436f75676878
The raw string seen in the DB is a serialized object.
One way of implementing this is to first join your string ArrayList into one delimited string, but I highly recommend against this.
In general it's bad practice to put a list into a single field of a table. What you should be doing is creating a separate table for Symptoms with a one-to-many relationship with Evaluation.
You need to be aware of denormalization while designing your objects when using JPA. In your case, consider the following questions :
What happens if you want to query evaluations with specific symptoms?
What happens if you want to query a list of all the symptoms?
What happens if you want to expand symptoms with some other detail, such as date when a symptom appeared?
If you are ever in a situation of trying to add a collection of something into a database field 99.9999% of the time you're doing it wrong. Symptoms should be their own entity, and you have a one-to-many or many-to-many relationship between evaluation and symptom, depending on what you require.
Edit :
To clarify my answer further, when designing object classes think about whether a field is a value object or an entity. A value object is something that cannot be broken down further and can be represented by a primitive, such as Date, String, Int, etc. Some examples could be an object ID, name, phone number, etc.
An entity is an object that can be expanded further, like the Evaluations object you created. Within Evaluations you have a list of Symptoms, and you're treating Symptoms as a value object. Is it a value object though? I can immediately think of some additional fields you could put into a Symptom object, and by denormalizing symptoms the way you did, you are also inputting tons of duplicate data into the database.
An evaluation object containing ["Fever", "Cough"] in your implementation will be input into the database as one field. But another evaluation object containing the same symptoms will be input into the database for that evaluation because you don't have a foreign key dependency or a separate table representing symptoms. On top of not being able to query symptoms in relation with evaluations, or not being able to query symptoms on their own.
I want to insert array of custom type into postgres with jdbc.
my sql schema:
CREATE TYPE element_pk_t AS (
workspace_id BIGINT,
element_id BIGINT,
history_id BIGINT
);
my java class:
public class ElementPK {
public Long workspaceId;
public Long elementId;
public Long historyId;
}
How should I do this in java with jdbc?
I've found tutorial regarding custom type https://docs.oracle.com/javase/tutorial/jdbc/basics/sqlcustommapping.html, but array of custom type is still unclear to me.
One trivial approach is using pure string style SQL statement, but I still prefer using PreparedStatement with setObject or setArray
If I understood you correctly, then, from the Java code, you need to generate query that looks, for example, like this:
INSERT INTO parent_table(elements)
VALUES (
ARRAY[
row(1, 2, 3)::element_pk,
row(4, 5, 6)::element_pk,
row(7, 8, 9)::element_pk
]);
Assuming that you have a table like the following:
CREATE TABLE parent_table(
id SERIAL PRIMARY KEY,
created_at TIMESTAMPTZ DEFAULT NOW(),
elements element_pk[]
)
And the Type like you described. If I were you, I wont implement it via an array. I would have use JSONB instead - in this way you wont lose an ability to use indexing. Of course, there is java.sql.Array out there, and you can still do it via the following:
Array array = connection.createArrayOf("public.element_pk", new ElementPK[]{
new ElementPK(1, 2, 3),
new ElementPK(9, 4, 6)
});
And then set the array, to PgPreparedStatement, but the thing is that internally PgPreparedStatement will enclose your elements within curly braces, which is ok, but each element will be represented by its toString method call result. I mean, assume your ElementPK toString looks like this:
#Override
public String toString() {
return "This is how it is implemented, really?";
}
then you will get the SQL like:
INSERT INTO parent_table (elements) VALUES ('{"This is how it is implemented, really?","This is how it is implemented, really?"}')
Again, it is maybe possible to adopt it, but from my perspective - at least having your logic within toString method is not that great, is it? Spare yourself and do the following:
CREATE TABLE via_jsonb(
elements JSONB
);
and then simply:
INSERT INTO via_jsonb VALUES(
'{
"workspace_id" : 1,
"element_id" : 2,
"history_id" : 3
}'
);
and in the Java code I would have simply create json from your object and set it as a string. Really, there are a lot of functions and cool features on JSONB out of the box.
Hope it helped, have a nice day!)
Follow up to the last part of #misha2045 answer.
If you still refuese to use JSONB for whatever reason you need to add parenthesis at the end and start of your toString method.
#Override
public String toString() {
return "("+this.field1+ ", " + this.field2+")";
}
Then set the array in the prepared statement
ps.setArray(1, con.createArrayOf("yourType", yourClassArray));
Is there any way to convert the string below to a list?
This string is retrieved after scanning a QR code.
CashRequest{
orderid='0',
user_id='nvHt2U5RnqUwXB4ZK37Zn1DXPV82',
userName='username',
userEmail='whateveremailthisis#email.blabla',
fullName='full name',
phoneNumber=0,
totalCash='$304.00',
totalRV='$34.00',
foods=[
Order{
userID='nvHt2U5RnqUwXB4ZK37Zn1DXPV82',
ProductID='-LMDiT7klgoXU8bQEM-4',
ProductName='Coke',
Quantity='4',
Price='1',
RedemptionPrice='10',
RedemptionValue='1'},
Order{
userID='nvHt2U5RnqUwXB4ZK37Zn1DXPV82',
ProductID='1000',
ProductName='Kunau Ring Ring Pradu',
Quantity='3',
Price='100',
RedemptionPrice='10',
RedemptionValue='10'
}
]
}
The desired output is to store it in firebase realtime database as below :
Well you have a few options. Since it is newline between values, you could use simple newline reads and compare if it starts with "reserved word that you are looking for" then substring from there, but that can get messy and a lot of bloat code.
The simplest way would be to do the known replace first.
Make a method that replaces all bad json keys with quote surrounded json keys like:
val myJsonCorrected = yourStringAbove.replace("Order", "\"Order"\")
repeat for all known entities until you have made it into valid json. Single ticks are fine for the values, but the keys need quotes as well.
Then simply create an object that matches the json format.
class CashRequestModel{
#SerializableName("orderid")
var orderID: Int? = null
etc.....
#SerializableName("foods")
var myFoods: ArrayList<OrderModel>? = null
}
class OrderMode {
#SerializableName("userID")
var userID: String? = null
#SerializableName("ProductID")
var userID: String? = null
etc..
}
Then simply convert it to JSON
val cashRequest = getGson().fromJson(cleanedUpJson, classTypeForCashRequest);
and your done. Now just use the list. Of course it would be better if you could get valid JSON without having to clean it up first, but it looks like the keys are known and you can easily code string replaces to fix the bad json before casting it to object that matches the structure.
Hope that helps.
I am trying to use the datastax java driver and retrieve the row as a JSON.
I do the classic
SELECT JSON * from myTable WHERE id=1 and this returns a Json formatted string on CQL.
e.g { "uuid" : "12324567-...." }
This works.
Now when, I try to do the same use the Java driver, I use (in scala)
val resultSet = session.execute(queryString)
I pick up one row from this result set using: "resultSet.one()".
This has the string I need, but how do I pick this up?
Experiment: resultSet.one().getColumnDefinitions.toString
Prints: Columns[ [json] (varchar) ]
Experiment: resultSet.one().toString()
Prints: Row[{"uuid": "3ce19e07-2280-4b31-9475-992bda608e70"}] <- String I need
How do I pick up a simple string that represents the JSON in my program, without trying to split the strings above ?
As noted in the the Cassandra documentation:
The results for SELECT JSON will only include a single column named [json]. This column will contain the same JSON-encoded map representation of a row that is used for INSERT JSON.
In order to access the JSON value of the returned row, you need to use one of the getString methods defined on the Row class to get the value of this column either by index or by name:
Row row = resultSet.one();
String json1 = row.getString(0);
String json2 = row.getString("[json]");
I am using the below mentioned MongoDB query in Java to find the maximun value of field price:
DBCursor cursor = coll.find(query,fields).sort(new BasicDBObject("price",1)).limit(1);
fields argument passing to coll.find function here is having the price field only.
So I am getting the output in the form:
{"price" : value}
Is there any way to get value only in the output without the field name and braces etc, so that it can be assigned to a variable or returned to the calling function etc.
Or if there is any other query or mechanism available that I can use for the same purpose.
Pls suggest..
Thanks & Regards
You can get value of price from the DBCursor object as follows.
while (cursor.hasNext()) {
Double price = (Double) cursor.next().get("price");
}
On the mongo shell you can do it as follows :
db.priceObj.find({},{_id:0, price:1}).sort({price:-1}).limit(1)[0].price
You cannot do this due to the fact that MongoDB communicates using BSON.
A single value like you want would be invalid BSON. It is easy enough to filter it out your side.