In my Oracle database, there is an Agreement table with a column effectivityDate with a data type of DATE. When I try to query a certain row
select * from agreement where id = 'GB'
it returns a row with this value:
id: GB
name: MUITF - Double bypass
...
effectivityDate: 7/2/2015
I created a Grails Domain class for this:
class Agreement implements Serializable {
String id
Date effectivityDate
static mapping = {
table "agreement"
varsion: false
id column: "id"
name column: "name"
...
effectivityDate column: "effectivityDate"
}
}
But when I tried to query it on groovy using:
Agreement a = Agreement.findById("GB")
println a
It return this object:
[id:GB, name:MUITF - Double bypass, ..., effectivityDate: 2015-07-01T16:00:00Z]
^^^^^^^^^^^^^^^^^^^^
My question is, why would the date fetched directly from the database different from the one retrieved by gorm? Does this have something to do with time zones?
Just seen in your profile you are from Philippines (PHT, GMT+8).
Since 2015-07-01T16:00:00Z === 2015-07-02T00:00:00+08:00, the most likely cause is that you are using the PHT time zone to display the date when querying the database and the GMT/Zulu time zone when querying/displaying with groovy/grails.
Related
Is it possible to add a look up to a mutation in GraphQL? Let's say something like an input type where one property is the result of another query.
createPerson(name: "Steve", gender: genders ( name: { eq: "mail" } ) { id } )
where genders ( name: { eq: "mail" } ) { id } would return exactly one result value
GraphQL allows you to:
"get what you want";
manipulate data on write;
customize response on read;
You can of course write a createPerson mutation resolver to:
ask another table for additional data (if missing arg);
write into DB;
But it doesn't affect (isn't suitable for) existing records.
You can also use read resolvers to update missing fields in records using field resolver - a kind of 'eventual consistency'.
Write person resolver to read a person record and additional person.gender field resolver to get value for missing gender value. The second one can be used to update the 'main' person [DB table] record:
read a missing value from other table;
write a value into person record on the 'main' table;
return value.
Next time person resolver will read gender value at once (from 'main' person table), [additional] field resolver won't be called at all.
This technique can be used to convert DB data without writing SQL/DB specific code (different syntax/types problems, safer on more complex logic) - it's enough to read each/all person's gender fields. Field resolver (and the other/old table) can be removed after that.
Ok i found myself in a simple but annoying problem. My mongo documents are using java.util.Date as id, and as you might guess the id gets converted (spring converters) to ObjectId, I can't update these documents because every time a new ObjectId(Date) is created get a completely different id even though the date is the same...
how do i force mongo to just use java.util.Date as an id?
providing the sample code:
public void updateNode(...node..) {
final MongoTemplate mongoTemplate = ...
final String collectionName = ...
final Query query = (new Query()).addCriteria(Criteria.where("time").is(node.getTime()));
final Update update = Update.update("time", node.getTime()).set("top", node.getTop())
.set("bottom", node.getBottom()).set("mid", node.getMid())
.set("startTime", node.getStartTime()).set("potential", node.isPotential());
mongoTemplate.upsert(query, update, MyClassNode.class, collectionName);
}
if I ran this code for the first time the objects are inserted into the database but with ObjectId... if the node.getTime() is a java.sql.Date then everything is fine.
if the node.getTime() is not a java.sql.Date I cannot update the document if it exists: why? because everytime the document is prepared it creates a new ObjectId the update and query will have two different _id field values and update fails.
On checking the documentation , i found the following details :
In MongoDB, each document stored in a collection requires a unique _id
field that acts as a primary key. If an inserted document omits the
_id field, the MongoDB driver automatically generates an ObjectId for the _id field.
This also applies to documents inserted through update operations with
upsert: true.
The following are common options for storing values for _id:
Use an ObjectId.
Use a natural unique identifier, if available. This saves space and
avoids an additional index.
Generate an auto-incrementing number.
What i understood from the documentation was that to avoid inserting the same document more than once, only use upsert: true if the query field is uniquely indexed.So, if this flag is set , you will find your id converted using ObjectId() to make it unique.
I'm creating a Grails 3 app with some tables from my Oracle 12c database scaffolded and while so far everything went fast, I came across one problematic table which doesn't have an ID column. It's just four VARCHAR2's. Also, in the Constraints tab of the Oracle SQL Developer, I don't see any of them defined as the Primary Key. How should one progress in such a scenario to successfully create a CRUD for this class?
I've tried telling Grails to use the row id as an ID but this only results in a "getLong not implemented for class oracle.jdbc.driver.T4CRowidAccessor" error when I try accessing the (to-be) scaffolded page. My code looks like this:
class AliasFrequencyDict {
String frequency
String unit
String description
String lang
static constraints = {
frequency maxSize: 10, sqlType: 'VARCHAR2'
unit maxSize: 1, sqlType: 'VARCHAR2'
description maxSize: 30, sqlType: 'VARCHAR2'
lang maxSize: 2, sqlType: 'VARCHAR2'
}
static mapping = {
sort 'frequency'
version false
id column: 'ROWID'
}
}
How should I solve this if I don't have an explicit ID column and I am not allowed to create one?
EDIT: So the only way I was able to progress so far was to use a composite key consisting of all the columns and then manually change the index view so that instead of this:
<f:table collection="${aliasFrequencyDict}" />
we now have this:
<f:table collection="${aliasFrequencyDictList}" properties="['frequency','unit','description','lang']"/>
This, however, doesn't let me access any of the existing entries or add new ones, as I guess I'd have to manually specify these properties there, too. It doesn't seem like it's nearly as easy to explicitly state them in the edit view, for example, as it is in the index, though (or to make the editing actually work, on top of that).
EDIT2: Also, from what I gathered, using ROWID isn't a good idea anyway. Oracle docs state:
Although you can use the ROWID pseudocolumn in the SELECT and WHERE
clause of a query, these pseudocolumn values are not actually stored
in the database. You cannot insert, update, or delete a value of the
ROWID pseudocolumn.
Thus, I'm out of ideas about how to progress :( Any help?
First, a simple example to describe my problem.
Model
public class User
{
public virtual String UserID { get; set; }
public virtual String UserName { get; set; }
public virtual DateTime LastLoginTime { get; set; }
}
Mapping
<id name="UserID" type="AnsiString">
<column name="p_UserID_vc" length="20"></column>
<generator class="assigned"/>
</id>
<property name="UserName" column="UserName_vc" type="AnsiString">
<property name="LastLoginTime" column="LastLoginTime_d" type="DateTime">
table
create table T_User
(
p_userid_vc VARCHAR2(20) not null,
username_vc VARCHAR2(50),
lastlogintime_d DATE,
)
Now ,there are one million users in this table. I create a oracle index in LastLoginTime. I use query like this:
var list = Responsity<User>.Where(q => q.LastLoginTime <= DateTime.Now &&
q.LastLoginTime >= DateTime.Now.AddDays(-7));
I use Nhibernate Profile to watchout the real sql string:
select t.p_UserID_vc
from T_User t
where t.lastlogintime_d >= TIMESTAMP '2012-03-19 16:58:32.00' /* :p1 */
and t.lastlogintime_d <= TIMESTAMP '2012-03-26 16:58:32.00' /* :p2 */
It didn't use the index. I think it should use 'to_date' ,so that it could use the index. How to config the mapping file?
There are a few reasons why it might not be using your index:
The datatype of LastLoginTime is a DATE, but the parameters are TIMESTAMPs, so it might be implicitly converting the column to a timestamp, which would mean it cannot use the index.
The Cost-Based-Optimizer (CBO) might be using statistics which indicate that using the index would be less efficient than not using it. For example, there might be very few rows in the table, or a histogram might tell the CBO that a large number of rows match the date range you're querying on. It's not uncommon for full table scans to outperform queries that use indexes.
Perhaps the statistics on the table are out-of-date, causing the CBO to make inaccurate estimates.
Do an explain plan on your query to determine what the cause is.
Note: the plan for a query that uses literal values (e.g. TIMESTAMP '...') could very well be different to that for a query that uses bind variables (e.g. p1 and p2). Run the explain plan for the query that is actually being executed.
just in case if anyone is still looking for an answer, hope this helps
the fix is to configure it with proper dialect, in my case it is NHibernate.Dialect.Oracle10gDialect
I'm using the Mongo shell to query my Mongo db. I want to use the timestamp contained in the ObjectID as part of my query and also as a column to extract into output. I have setup Mongo to create ObjectIDs on its own.
My problem is I can not find out how to work with the ObjectID to extract its timestamp.
Here are the queries I am trying to get working. The 'createdDate' field is a placeholder; not sure what the correct field is:
//Find everything created since 1/1/2011
db.myCollection.find({date: {$gt: new Date(2011,1,1)}});
//Find everything and return their createdDates
db.myCollection.find({},{createdDate:1});
getTimestamp()
The function you need is this one, it's included for you already in the shell:
ObjectId.prototype.getTimestamp = function() {
return new Date(parseInt(this.toString().slice(0,8), 16)*1000);
}
References
Check out this section from the docs:
Extract insertion times from _id rather than having a separate timestamp field
This unit test also demostrates the same:
mongo / jstests / objid6.js
Example using the Mongo shell:
> db.col.insert( { name: "Foo" } );
> var doc = db.col.findOne( { name: "Foo" } );
> var timestamp = doc._id.getTimestamp();
> print(timestamp);
Wed Sep 07 2011 18:37:37 GMT+1000 (AUS Eastern Standard Time)
> printjson(timestamp);
ISODate("2011-09-07T08:37:37Z")
This question is helpful to understand of how to use the _id's embedded timestamp in query situations (refers to the Mongo Extended JSON documentation). This is how it's done:
col.find({...,
'_id' : {'$lt' : {'$oid' : '50314b8e9bcf000000000000'}}
})
finds documents created earlier than the one that's given by oid. Used together with natural sorting and limiting you can utilize BSON _ids to create Twitter-like API queries (give me the last OID you have and I'll provide twenty more)
In python you can do this:
>>> from bson.objectid import ObjectId
>>> gen_time = datetime.datetime(2010, 1, 1)
>>> dummy_id = ObjectId.from_datetime(gen_time)
>>> result = collection.find({"_id": {"$lt": dummy_id}})
I think, ObjectId.from_datetime() - its a useful method of standard bson lib
Maybe other language bindings have alternative builtin function.
Source: http://api.mongodb.org/python/current/api/bson/objectid.html
To use the timestamp contained in the ObjectId and return documents created after a certain date, you can use $where with a function.
e.g.
db.yourcollection.find( {
$where: function() {
return this._id.getTimestamp() > new Date("2020-10-01")
}
});
The function needs to return a truthy value for that document to be included in the results. Reference: $where
Mongo date objects can seem a bit peculiar though. See the mongo Date() documentation for constructor details.
excerpt:
You can specify a particular date by passing an ISO-8601 date string with a year within the inclusive range 0 through 9999 to the new Date() constructor or the ISODate() function. These functions accept the following formats:
new Date("<YYYY-mm-dd>") returns the ISODate with the specified date.
new Date("<YYYY-mm-ddTHH:MM:ss>") specifies the datetime in the client’s local timezone and returns the ISODate with the specified datetime in UTC.
new Date("<YYYY-mm-ddTHH:MM:ssZ>") specifies the datetime in UTC and returns the ISODate with the specified datetime in UTC.
new Date(<integer>) specifies the datetime as milliseconds since the Unix epoch (Jan 1, 1970), and returns the resulting ISODate instance.