How to convert Instant to Int - java

In my app I have AlarmManager to set Scheduled notification.
In order to have unique notification to each Item, I need to set unique id to each pending intent, otherwise the notification run over each other.
my problem is that my PK is string, not an int. my closest thing to Int in my Item model is Instant, which represent the time that the notification should send, and It's unique.
And because PendingIntent id is only an int, how can I convert Instant to Int?
Or should I take another approach and create data field in my model just to hold the pending intent ID?
In my understanding I shoudn't convert it directly cause it will mess with the date/time and potentially(?) won't by unique

That should work I think:
instant.get(ChronoField.INSTANT_SECONDS)

Simple String to int conversion could made with hashCode. But a hash code is by definition not unique. If possible then changing the type from int to String is probably the best option. If you really need a conversion I would recommend you create something like and IndexProvider.
public interface IndexProvider {
/**
* Idempotent index provider for id conversion.
* Be aware of memory consumption because the implementations are allowed to cache id's.
* #param id unique id
* #return a cached unique id or a new unique id
*/
int getIndex(String id);
}
This would allow you to simple solve the problem. You could use a map in the implementation for holding the String id's . Other idea would be to solve this problem in the database. For example a new table which holds you an int id for every String id. At the end you will have to modify something and you will have Pro's and Contra's for every approach.
This is probably not a full answer but I have not enough reputation for commenting.

Related

Firebase Real Time DB - DatabaseReference.push().getKey() is a TimeStamp

According to the Documentation, the below code can set a timestamp as the key of the node using push() in the Realtime Database.
public void uploadToDB(String s) {
databaseReference.push().setValue(s);
}
The returned key are below of my push(), as an example:
a) -MpfCu14jtIkEk28D3CB
b) -MpfCxv_Nzv3YJ87MfZH
My question is:
are they timestamp?
if yes, can I decode it back to a readable timestamp?
are they timestamp?
No, those pushed IDs are not timestamps. However, it contains a time component.
As Michael Lehenbauer mentioned in this blog article:
Push IDs are string identifiers that are generated client-side. They are a combination of a timestamp and some random bits. The timestamp ensures they are ordered chronologically, and the random bits ensure that each ID is unique, even if thousands of people are creating push IDs at the same time.
And to answer the second question:
if yes, can I decode it back to readable timestamp?
If you reverse the engineering, probably yes. Please check the following answer:
How are Firebase IDs generated?
But would not count on that. To have an order according to a time component, then you should add a property of type "timestamp", as explained in my answer from the following post:
How to save the current date/time when I add new value to Firebase Realtime Database

How to select items in date range in DynamoDB

How can I select all items within a given date range?
SELECT * FROM GameScores where createdAt >= start_date && createAt <=end_date
I want to make a query like this. Do I need to crate a global secondary index or not?
I've tried this
public void getItemsByDate(Date start, Date end) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String stringStart = df.format(start);
String stringEnd = df.format(end);
ScanSpec scanSpec = new ScanSpec();
scanSpec.withFilterExpression("CreatedAt BETWEEN :from AND :to")
.withValueMap(
new ValueMap()
.withString(":from", stringStart)
.withString(":to", stringEnd));
ItemCollection<ScanOutcome> items = null;
items = gamesScoresTable.scan(scanSpec);
}
But it doesn't work, I'm getting less results than expected.
I can answer your questions, but to suggest any real solution, I would need to see the general shape of your data, as well as what your GameScore's primary key is.
TLDR;
Setup your table so that you can retrieve data with queries, rather than scans and filters, and then create indexes to support lesser used access patterns and improve querying flexibility. Because of how fast reads are when providing the full (or, although not as fast, partial) primary key, i.e. using queries, DynamoDB is optimal when table structure is driven by the application's access patterns.
When designing your tables, keep in mind NoSQL design best practices, as well as best practices for querying and scanning and it will pay dividends in the long run.
Explanations
Question 1
How can I select all items within a given date range?
To answer this, I'd like to break that question down a little more. Let's start with: How can I select all items?
This, you have already accomplished. A scan is a great way to retrieve all items in your table, and unless you have all your items within one partition, it is the only way to retrieve all the items in your table. Scans can be helpful when you have to access data by unknown keys.
Scans, however, have limitations, and as your table grows in size they'll cost you in both performance and dollars. A single scan can only retrieve a maximum of 1MB of data, of a single partition, and is capped at that partition's read capacity. When a scan tops out at either limitation, consecutive scans will happen sequentially. Meaning a scan on a large table could take multiple round trips.
On top of that, with scans you consume read capacity based on the size of the item, no matter how much (or little) data is returned. If you only request a small amount of attributes in your ProjectionExpression, and your FilterExpression eliminates 90% of the items in your table, you still paid to read the entire table.
You can optimize performance of scans using Parallel Scans, but if you require an entire table scan for an access pattern that happens frequently for your application, you should consider restructuring your table. More about scans.
Let's now look at: How can I select all items, based on some criteria?
The ideal way to accomplish retrieving data based on some criteria (in your case SELECT * FROM GameScores where createdAt >= start_date && createAt <=end_date) would be to query the base table (or index). To do so, per the documentation:
You must provide the name of the partition key attribute and a single value for that attribute. Query returns all items with that partition key value.
Like the documentation says, querying a partition will return all of its values. If your GameScores table has a partition key of GameName, then a query for GameName = PacMan will return all Items with that partition key. Other GameName partitions, however, will not be captured in this query.
If you need more depth in your query:
Optionally, you can provide a sort key attribute and use a comparison operator to refine the search results.
Here's a list of all the possible comparison operators you can use with your sort key. This is where you can leverage a between comparison operator in the KeyConditionExpression of your query operation. Something like: GameName = PacMan AND createdAt BETWEEN time1 AND time2 will work, if createdAt is the sort key of the table or index that you are querying.
If it is not the sort key, you might have the answer to your second question.
Question 2
Do I need to create a Global Secondary Index?
Let's start with: Do I need to create an index?
If your base table data structure does not fit some amount of access patterns for your application, you might need to. However, in DynamoDB, the denormalization of data also support more access patterns. I would recommend watching this video on how to structure your data.
Moving onto: Do I need to create a GSI?
GSIs do not support strong read consistency, so if you need that, you'll need to go with a Local Secondary Index (LSI). However, if you've already created your base table, you won't be able to create an LSI. Another difference between the two is the primary key: a GSI can have a different partition and sort key as the base table, while an LSI will only be able to differ in sort key. More about indexes.

Can firebase generate an unique ID as we wish?

Like firebase generating uid. Can firebase generate an unique ID as we wish? If it is possible? how to write a code for it in the following order?
For example PRO00013, PRO00014, PRO00015....
I am asking here, because I'm working in a project for online shopping. when a user adds a product to their inventory it needs to assign an id for every product. that is must be in the human readable format. If it is not possible, just tell me no, I can accept that answer.
You can just call .push() to get randomUUID and then ref.child(randomUUID).setValue(object)
where the object can contain field ID such as PRO00013.
If this doesn't fit your needs you can just place ref.child("PRO00013").setValue(object) and not include field id in this object.
Now you want to get id PRO00014 for the next pushed object. This ain't gonna happen with firebase.
But you can get the last ID added in this ref with query on
ref.orderByKey().limitToLast(1);
Now you have the last added object from this node and you can simply get the key which will be PRO00013.
1. Cast it to String
2. Remove "PRO" from this string
3. Cast the remaining to integer
4. Add 1 to this integer
5. Create new string variable and give it value "PRO" + the new integer
6. Now push the object in ref.(the new string variable).setValue(object).
Now I don't know if you gonna implement this logic in a cloud function accepting some sort of params but if this is the case - this should work just fine.
I also want to know WHY xD

Create Unique Message Id Like whats app

I am creating chat application so want generate unique message id .
Is it possible never create duplicate message id.
MongoDB's ObjectId is pretty complex is probably one of the good randomness from a unique id point of view.
So you can take a sneak peek in their source code to see how they generate it.
Leaving the definition from their official documentation here for posterity:
ObjectIds are small, likely unique, fast to generate, and ordered.
ObjectId values consists of 12-bytes, where the first four bytes are a
timestamp that reflect the ObjectId’s creation, specifically:
a 4-byte value representing the seconds since the Unix epoch,
a 3-byte machine identifier,
a 2-byte process id, and
a 3-byte counter, starting with a random value.
Example of Mongo's ObjectId:
ObjectId("507f1f77bcf86cd799439011")
There could be many ways to generate one! One common way would be to generate timestamp value and use it as a id which is also unique.
For example you can do this:
public int createID(){
Date now = new Date();
int id = Integer.parseInt(new SimpleDateFormat("ddHHmmss", Locale.US).format(now));
return id; }
you can also try and make it string and add any specific string format with it to make it more unique according to ur apps need!
base on your poor description, you can create compound id. for example you can create your ides with user id+timestamp. and if you use this pattern, your user id length must be same for all ides. so if it is not, you have to add "0" befor your current id to obtain equal length for all of your user ides
for better description:
String uniquemsgid= userid+ System.currentTimeMillis();
as a matter of fact, your user have a unique id an timestamp is unique for this user.
caution: if you use only timestamp or a date with any format, this method cant guarantee a unique message id. because two user can create a message at a moment
You can make a Random randomId= new Random();
int id = randLan.nextInt(99999) + 1;
Then you check if Id is already given, and if yes, try again, if not, you have an Id.
if(randomId == someOtherId), do same process again.
You might want to use device IMEI number for this, which is always unique and quite easy to get.
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Add above permission in your manifest file and then use the below two lines to get the IMEI.
TelephonyManager mngr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
long id = Long.parseLong(mngr.getDeviceId());

How can I insert common data into a temp table from disparate schemas?

I am not sure how to solve this problem:
We import order information from a variety of online vendors ( Amazon, Newegg etc ). Each vendor has their own specific terminology and structure for their orders that we have mirrored into a database. Our data imports into the database with no issues, however the problem I am faced with is to write a method that will extract required fields from the database, regardless of the schema.
For instance assume we have the following structures:
Newegg structure:
"OrderNumber" integer NOT NULL, -- The Order Number
"InvoiceNumber" integer, -- The invoice number
"OrderDate" timestamp without time zone, -- Create date.
Amazon structure:
"amazonOrderId" character varying(25) NOT NULL, -- Amazon's unique, displayable identifier for an order.
"merchant-order-id" integer DEFAULT 0, -- A unique identifier optionally supplied for the order by the Merchant.
"purchase-date" timestamp with time zone, -- The date the order was placed.
How can I select these items and place them into a temporary table for me to query against?
The temporary table could look like:
"OrderNumber" character varying(25) NOT NULL,
"TransactionId" integer,
"PurchaseDate" timestamp with time zone
I understand that some of the databases represent an order number with an integer and others a character varying; to handle that I plan on casting the datatypes to String values.
Does anyone have a suggestion for me to read about that will help me figure this out?
I don't need an exact answer, just a nudge in the right direction.
The data will be consumed by Java, so if any particular Java classes will help, feel free to suggest them.
First, you can create a VIEW to provide this functionality:
CREATE VIEW orders AS
SELECT '1'::int AS source -- or any other tag to identify source
,"OrderNumber"::text AS order_nr
,"InvoiceNumber" AS tansaction_id -- no cast .. is int already
,"OrderDate" AT TIME ZONE 'UTC' AS purchase_date -- !! see explanation
FROM tbl_newegg
UNION ALL -- not UNION!
SELECT 2
"amazonOrderId"
,"merchant-order-id"
,"purchase-date"
FROM tbl_amazon;
You can query this view like any other table:
SELECT * FROM orders WHERE order_nr = 123 AND source = 2;
The source is necessary if the order_nr is not unique. How else would you guarantee unique order-numbers over different sources?
A timestamp without time zone is an ambiguous in a global context. It's only good in connection with its time zone. If you mix timestamp and timestamptz, you need to place the timestamp at a certain time zone with the AT TIME ZONE construct to make this work. For more explanation read this related answer.
I use UTC as time zone, you might want to provide a different one. A simple cast "OrderDate"::timestamptz would assume your current time zone. AT TIME ZONE applied to a timestamp results in timestamptz. That's why I did not add another cast.
While you can, I advise not to use camel-case identifiers in PostgreSQL ever. Avoids many kinds of possible confusion. Note the lower case identifiers (without the now unnecessary double-quotes) I supplied.
Don't use varchar(25) as type for the order_nr. Just use text without arbitrary length modifier if it has to be a string. If all order numbers consist of digits exclusively, integer or bigint would be faster.
Performance
One way to make this fast would be to materialize the view. I.e., write the result into a (temporary) table:
CREATE TEMP TABLE tmp_orders AS
SELECT * FROM orders;
ANALYZE tmp_orders; -- temp tables are not auto-analyzed!
ALTER TABLE tmp_orders
ADD constraint orders_pk PRIMARY KEY (order_nr, source);
You need an index. In my example, the primary key constraint provides the index automatically.
If your tables are big, make sure you have enough temporary buffers to handle this in RAM before you create the temp table. Else it will actually slow you down.
SET temp_buffers = 1000MB;
Has to be the first call to temp objects in your session. Don't set it high globally, just for your session. A temp table is dropped automatically at the end of your session anyway.
To get an estimate how much RAM you need, create the table once and measure:
SELECT pg_size_pretty(pg_total_relation_size('tmp_orders'));
More on object sizes under this related question on dba.SE.
All the overhead only pays if you have to process a number of queries within one session. For other use cases there are other solutions. If you know the source table at the time of the query, it would be much faster to direct your query to the source table instead. If you don't, I would question the uniqueness of your order_nr once more. If it is, in fact, guaranteed to be unique you can drop the column source I introduced.
For only one or a few queries, it might be faster to use the view instead of the materialized view.
I would also consider a plpgsql function that queries one table after the other until the record is found. Might be cheaper for a couple of queries, considering the overhead. Indexes for every table needed of course.
Also, if you stick to text or varchar for your order_nr, consider COLLATE "C" for it.
Sounds like you need to create an abstract class that will define the basics of interacting with the data, then derive a class per database schema you need to access. This will allow the core code to operate on a single object type, and each implementation can then specify the queries in a form specific to that database schema.
Something like:
public class Order
{
private String orderNumber;
private BigDecimal orderTotal;
... etc ...
}
public abstract class AbstractOrderInformation
{
public abstract ArrayList<Order> getOrders();
...
}
with a Newegg class:
public class NeweggOrderInformation extends AbstractOrderInformation
{
public ArrayList<Order> getOrders() {
... do the work of getting the newegg order
}
...
}
Then you can have an arbitrarily large number of formats and when you need information, you can just iterate over all the implementations and get the Orders from each.

Categories