I am trying to update one value of my document atomically using findAndModify, which according to my reading is atomic in the same document. According to my Unit test the values are not modified.
I'm using mongoTemplate in Java, and my code looks like
public OfferConfiguration IncreaseStock(OfferConfiguration offerConfiguration) {
Query query = new Query(Criteria.where("_id").is(offerConfiguration.getId()));
Update update = new Update().inc("stock", 1);
return mongoTemplate.findAndModify(query, update, OfferConfiguration.class);
}
public OfferConfiguration findAndDecreaseStock(String offerId ) {
Query query = new Query(Criteria.where("_id").is(offerId).and("stock").gt(0));
Update update = new Update().inc("stock", -1);
return mongoTemplate.findAndModify(query, update, OfferConfiguration.class);
}
Stock has type Long, and I can see that when I use a criteria in the find:
Query query = new Query(Criteria.where("_id").is(offerId).and("stock").gt(0));
return mongoTemplate.findOne(query, OfferConfiguration.class);
It returns only the values whose stock is greater than 0.
Any idea what is wrong in my code?
FindAndModify will return the original document after making the update to it by default.
If you want to get back the modified document you have to pass it the optional new option.
It seems you already found that the way to do that is by adding returnNew(true) to the findAndModify command.
Related
ViewObject VO = getViewObjectFromAMImpl("EOView2", "AppModuleDataControl");
Row[] selectedRows = VO.getFilteredRows("tSelect", true);
int counter = 0;
ADFContext adfCtx = ADFContext.getCurrent();
SecurityContext secCntx = adfCtx.getSecurityContext();
String _user = secCntx.getUserName();
//Date vDate = getMinDate();
java.sql.Timestamp startDate = null;
for (Row r : selectedRows) {
startDate = (java.sql.Timestamp) r.getAttribute("StartDate");
if ("E".equals(r.getAttribute("SrcType"))) {
r.setAttribute("Type","S");
r.setAttribute("UpdatedBy", new Date());
r.setAttribute("LastUpdateDate", new Date());
counter++;
}
}
System.out.println("printing count"+counter);
if (counter == 0) {
JSFUtils.addFacesErrorMessage((String) JSFUtils.resolveExpression("No records Approved."));
} else {
Commit();
JSFUtils.addFacesInformationMessage((String) JSFUtils.resolveExpression(" records Approved successfully."));
AdfFacesContext.getCurrentInstance().addPartialTarget(hearderTableBind);
}
approvePopup.cancel();
From the above code i will get the selected rows with key and value pair. I want to add those rows ( Key and Value) to a list and i need to call the procedure. Could you please tell me which is the best possible way to achive this.
I want to call the procedure with key and value pair( Multiple values will come)
You should read the doc at
https://docs.oracle.com/en/middleware/developer-tools/adf/12.2.1.4/develop/extending-business-components-functionality1.html#GUID-B93C7B79-73C9-4434-B12E-A7E23479969A
However, I fail to understand why you need to call a pl/sql procedure at all.
You should be able to do everything in ADF or call a procedure directly without iterating over the data just to set some values.
It's not a good idea to change values in ADF, then call a procedure and assume that the framework somehow knows the changes. The procedure runs in the DB in a different transaction. ADF doesn't know about changes done in the function. The function doesn't know about the changes done in ADF until you post them to the DB.
I was wonder if I could delete some columns of some rows with timestamp without scanning the whole database
my code is like below:
public static final void deleteBatch(long date, String column, String...ids) throws Exception{
Connection con = null; // connection instance
HTable table = null; // htable instance
List<Delete> deletes = new ArrayList<Delete>(ids.length);
for(int i = 0; i < ids.length; i++){
String id = ids[i];
Delete delete = new Delete(id.getBytes());
delete.addColumn(/* CF */, Bytes.toString(column));
/*
also tried:
delete.addColumn(/* CF */, Bytes.toString(column), date);
*/
delete.setTimestamp(date);
deletes.add(delete);
}
table.delete(deletes);
table.close();
}
this works, but deletes all column prior to given date,
I want something like this:
Delete delete = new Delete(id.getBytes());
delete.setTimestamp(date-1, date);
I don't want to delete prior or after a specific date, I want to delete exact time range I give.
Also my MaxVersion of HTableDescriptor is set to Integer.MAX_VALUE to keep all changes.
as mentioned in the Delete API Documentation:
Specifying timestamps, deleteFamily and deleteColumns will delete all
versions with a timestamp less than or equal to that passed
it delets all columns which their timestamps are equal or less than given date.
how can I achieve that?
any answer appreciated
After struggling for weeks I found a solution for this problem.
the apache HBase has a feature called coprocessor which hosts and manages the core execution of data level operations (get, delete, put ...) and can be overrided(developed) for custom computions like data aggregation and bulk processing against the data outside the client scope.
there are some basic implemention for common problems like bulk delete and etc..
I am making the following query which works and updates the info into the database as expected. But is there a way I can get an output from Single < UpdateResult >?
public Single<UpdateResult> update(UpdateEventRequest request) {
return client.rxUpdateWithParams(
"UPDATE mydb.sample SET sta_cd=?, some_ts=current_timestamp WHERE id=? RETURNING sta_cd",
new JsonArray(Arrays.asList(sta_cd, id)));
}
From the following e variable, I was hoping to get the value "10012". But it doesn't seem possible. Tried with map, flatmap and just see options available in e. The only result data in e is 'keys' which is an empty list and 'updated' which is an integer value of 1. My DB is postgres and was expecting results from from Single < UpdateResult > since am using 'RETURNING' in the query.
I have done the same for an insert operation which works but that is via the method rxQueryWithParams() and that returns a Single < ResultSet > instead. Thus wondering if this is even possible. Been having a look at docs and maybe this is not possible as an update query is returning a Single < UpdateResult > . Looking for advice if this is possible, to return data from an update query or a way around this. Please advice. Thanks.
Single<UpdateResult> result = someClass.update("10012", "78632");
result.subscribe(
e -> {
System.out.println("success: " + e); // I land here as expected
},
error -> {
System.out.println("error: " + error);
}
);
Because you are using RETURNING in these commands, treat these INSERT and UPDATE commands as queries.
Run them through rxQueryWithParams() so you can retrieve the results.
When you run rxUpdateWithParams(), the UpdateResult contains only the number of rows affected.
I am trying to write Criteria in Hibernate, My desired output is if column empfield1's value is not 'REGULARIZE' then update else do not update record.
i have tried below one.
Session session = factory1.openSession();
Criteria criteria=session.createCriteria(EmployeePunch.class);
criteria.add(Restrictions.ne("empField1","REGULARIZE"));
EmployeePunch empPunch = (EmployeePunch)criteria.uniqueResult();
empPunch.setId(empPuncId);
empPunch.setSigninTime(inTime);
empPunch.setSigninDate(dateOfUpdate);
empPunch.setSignoutTime(outTime);
empPunch.setPresent(presentStatus);
empPunch.setLastUpdateBy(empcode);
empPunch.setLastUpdateDate(time);
empPunch.setEmpField1(remark);
session.saveOrUpdate(empPunch);
tx.commit();
but it gives me error
Exception : query did not return a unique result: 527
I think you forget to give id without giving id hibernate will return multiple records with empField1="REGULARIZE"
You should give id as well like below:
Criteria criteria=session.createCriteria(EmployeePunch.class);
criteria.add(Restrictions.ne("empField1","REGULARIZE"))
.add(Restrictions.eq("empPuncId",empPuncId));
Now it will return single matching record and then update it.
That means ,With that criteria there are multiple records are there in your Database.
To know how many records are there,
Try
List<EmployeePunch> emps = (ArrayList<EmployeePunch>)criteria.list();
So that emps will give you a list of EmployeePunch's which meets the criteria.
Then iterate the list and see how many items are there inside database.
Why not use a HQL in this way?
Query query = session.createQuery("update EmployeePunch set signinTime = :signinTime, signinDate = :signinDate where empField1 = 'REGULARIZE').setParameter("signinTime",signinTime).setParameter("signinDate",signinDate);
int updateRecordCount = query.executeUpdate();
Of course, you have to set values for other properties (except for Id if it is your #Id field); in updateRecordCount you get the count of updated records.
Im trying to update multiple records via an ATG class extending GenericService.
However im running against a roadblock.
How do I do a multiple insert query where i can keep adding all the items / rows into the cached object and then do a single command sync with the table using item.add() ?
Sample code
the first part is to clear out the rows in the table before insertion happens (mighty helpful if anyone knows of a way to clear all rows in a table without having to loop through and delete one by one).
MutableRepository repo = (MutableRepository) feedRepository;
RepositoryView view = null;
try{
view = getFeedRepository().getView(getFeedRepositoryFeedDataDescriptorName());
RepositoryItem[] items = null;
if(view != null){
QueryBuilder qb = view.getQueryBuilder();
Query getFeedsQuery = qb.createUnconstrainedQuery();
items = view.executeQuery(getFeedsQuery);
}
if(items != null && items.length>0){
// remove all items in the repository
for(RepositoryItem item :items){
repo.removeItem(item.getRepositoryId(), getFeedRepositoryFeedDataDescriptorName());
}
}
for(RSSFeedObject rfo : feedEntries){
MutableRepositoryItem feedItem = repo.createItem(getFeedRepositoryFeedDataDescriptorName());
feedItem.setPropertyValue(DB_COL_AUTHOR, rfo.getAuthor());
feedItem.setPropertyValue(DB_COL_FEEDURL, rfo.getFeedUrl());
feedItem.setPropertyValue(DB_COL_TITLE, rfo.getTitle());
feedItem.setPropertyValue(DB_COL_FEEDURL, rfo.getPublishedDate());
RepositoryItem item = repo.addItem(feedItem) ;
}
The way I interpret your question is that you want to add multiple repository items to your repository but you want to do it fairly efficiently at a database level. I suggest you make use of the Java Transaction API as recommended in the ATG documentation, like so:
TransactionManager tm = ...
TransactionDemarcation td = new TransactionDemarcation ();
try {
try {
td.begin (tm);
... do repository item work ...
}
finally {
td.end ();
}
}
catch (TransactionDemarcationException exc) {
... handle the exception ...
}
Assuming you are using a SQL repository in your example, the SQL INSERT statements will be issued after each call to addItem but will not be committed until/if the transaction completes successfully.
ATG does not provide support for deleting multiple records in a single SQL statement. You can use transactions, as #chrisjleu suggests, but there is no way to do the equivalent of a DELETE WHERE ID IN {"1", "2", ...}. Your code looks correct.
It is possible to invoke stored procedures or execute custom SQL through an ATG Repository, but that isn't generally recommended for portability/maintenance reasons. If you did that, you would also need to flush the appropriate portions of the item/query caches manually.