I am new at using MongoDB. I have it filled with receipts, for example: one receipt looks like this :
{
"_id" : {
"$oid" : "510fa057c6f818c2bfd0b279"
} ,
"StoreName" : "Metro" ,
"StoreNumber" : 521 ,
"Items" : [ {
"ItemName" : "Battery" ,
"ItemManufacturer" : "Duracell" ,
"ItemPrice" : 12 ,
"ItemQuantity" : 2 ,
"ItemTotalPrice" : 24
} ,
{
"ItemName" : "TV CRT 25 inch" ,
"ItemManufacturer" : "Toshiba" ,
"ItemPrice" : 1659 ,
"ItemQuantity" : 1 ,
"ItemTotalPrice" : 1659
} ,
{
"ItemName" : "Mobile" ,
"ItemManufacturer" : "Nokia" ,
"ItemPrice" : 2966 ,
"ItemQuantity" : 4 ,
"ItemTotalPrice" : 11864
}
] ,
"Date" : {
"$date" : "2012-06-16T01:21:11.758Z"
} ,
"Total" : 13547
}
I need to make a query where I specify a range of dates to get all the receipts in that range. I've tried the following query, but it returns nothing.
BasicDBObject query =
new BasicDBObject(
"Date",
new BasicDBObject(
"$gt",
"2012-06-20T10:05:21.968Z"
).append(
"$lte",
"2012-09-24T05:29:43.031Z"
)
);
MongoDB dates work in conjunction with java.util.Date. Change your query to something like this :
Date start = new java.util.Date(2012, 06, 20, 10, 05);
Date end = new java.util.Date(2012, 06, 20, 10, 30);
BasicDBObject query = new BasicDBObject("Date",
new BasicDBObject("$gt", start)).
append("$lte", end) ));
You could try:
Date gtDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse("2012-06-20T10:05:21.968");
Date lteDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse("2012-09-24T05:29:43.031");
BasicDBObject dateQueryObj = new BasicDBObject("Date", new BasicDBObject("$gt", gtDate).append("$lte", lteDate));
DBCursor cursor = collection.find(dateQueryObj);
Related
I have a collection "prefs" with document structure as below
{
_id: {
userId: "abc"
},
val: {
status: 1,
prefs: [
{
value: "condition",
lastSent: ISODate("2017-07-17T23:46:53.717Z")
}
],
deal: 2,
prevDeal: 3
}
}
I am trying to update the date field lastSent with a condition on userId and status. Below are the queries that I derieved from my Java code.
Select Query:
{ "_id" : { "userId" : "abc"} , "val.status" : 1 , "val.prefs.value" : "condition"}
Update Query:
{ "$set" : { "val.prefs.$.lastSent" : { "$date" : "2017-07-17T23:50:07.009Z"}}}
The above query is giving error as follows:
The dotted field 'prefs.$.lastSent' in 'val.prefs.$.lastSent' is not valid for storage.
How do I achieve this?
Below is my Java code:
BasicDBObject _idObject = new BasicDBObject();
_idObject.put("userId", "abc");
BasicDBObject _selectQuery = new BasicDBObject();
_selectQuery.put("_id", _idObject);
_selectQuery.put("val.status", 1);
_selectQuery.put("val.prefs.value", "condition");
BasicDBObject _valueUpdateQuery = new BasicDBObject();
_valueUpdateQuery.put("prefs.$.lastSent", lastSent);
BasicDBObject _updateQuery = new BasicDBObject();
_updateQuery.put("$set", new BasicDBObject("val", _valueUpdateQuery));
prefs.update(_selectQuery, _updateQuery, true, true);
I just tested with your code in mongo shell this codes works fine you don't have to mention
$date
and i used this code for updating date
db.getCollection('tester').update({ "_id" : { "userId" : "abc"} , "val.status" : 1 , "val.prefs.value" : "condition"},{ "$set" : { "val.prefs.$.lastSent" : new Date()}})
I've this document:
{
"_id" : ObjectId("54140782b6d2ca6018585093"),
"user_id" : ObjectId("53f4ae1ae750619418a20467"),
"date" : ISODate("2014-09-13T08:59:46.709Z"),
"type" : 0,
"tot" : 2,
"additional_info" : {
"item_id" : ObjectId("540986159ef9ebafd3dcb5d0"),
"shop_id" : ObjectId("53f4cc5a6e09f788a103d0a4"),
"ap_id" : ObjectId("53f4cc5a6e09f788a103d0a5")
},
"transactions" : [
{
"_id" : ObjectId("54140782b6d2ca6018585091"),
"date_creation" : ISODate("2014-09-13T08:59:46.711Z"),
"type" : -1
},
{
"_id" : ObjectId("54140782b6d2ca6018585092"),
"date_creation" : ISODate("2014-09-13T08:59:46.788Z"),
"type" : 1
}
]
}
and I need to add 2 more field to the first transaction opbject:
- date_execution: date
- result: this bson document
{ "server_used" : "xxx.xxx.xxx.xxx:27017" , "ok" : 1 , "n" : 1 , "updated_executed" : true} (m_OR.getDocument() in the following code example)
to obtaing that document
{
"_id" : ObjectId("54140811b6d25137753c1a1a"),
"user_id" : ObjectId("53f4ae1ae750619418a20467"),
"date" : ISODate("2014-09-13T09:02:09.098Z"),
"type" : 0,
"tot" : 2,
"additional_info" : {
"item_id" : ObjectId("540986159ef9ebafd3dcb5d0"),
"shop_id" : ObjectId("53f4cc5a6e09f788a103d0a4"),
"ap_id" : ObjectId("53f4cc5a6e09f788a103d0a5")
},
"transactions" : [
{
"_id" : ObjectId("54140811b6d25137753c1a18"),
"date_creation" : ISODate("2014-09-13T09:02:09.100Z"),
"type" : -1,
"result" : {
"server_used" : "xxx.xxx.xxx.xxx:27017",
"ok" : 1,
"n" : 1,
"updated_executed" : true
},
"date_execution" : ISODate("2014-09-13T09:02:15.370Z")
},
{
"_id" : ObjectId("54140811b6d25137753c1a19"),
"date_creation" : ISODate("2014-09-13T09:02:09.179Z"),
"type" : 1
}
]
}
The only way I was able to do that is the do 2 separates updates (update is a my wrapper funciont that execute the real updates in mongodb and it works fine):
// where
BasicDBObject query = new BasicDBObject();
query.append("transactions._id", m_Task.ID());
// new value for result - 1st upd
BasicDBObject value = new BasicDBObject();
value.put("$set",new BasicDBObject("transactions.$.date_execution",new Date()));
update(this._systemDB, "activities", query, value);
// new value for date_execution - 2nd upd
value = new BasicDBObject();
value.put("$set",new BasicDBObject("transactions.$.result",m_OR.getDocument()));
update(this._systemDB, "activities", query, value);
If I try to do this:
BasicDBObject value = new BasicDBObject();
value.put("$set",new BasicDBObject("transactions.$.date_execution",new Date()));
value.put("$set",new BasicDBObject("transactions.$.result",m_OR.getDocument()));
or = update(this._systemDB, "activities", query, value);
just the 2nd set will be applied.
Is there any way do avoid the double execution and apply the update with just one call?
Basic rule of "hash/map" objects is that you can only have one key. It's the "highlander" rule ( "There can be only one" ) applied in general reason. So just apply differently:
BasicDBObject value = new BasicDBObject();
value.put("$set",
new BasicDBObject("transactions.$.date_execution",new Date())
.add( new BasicDBObject("transactions.$.result",m_OR.getDocument() )
);
So basically "both" field arguments are part of the "$set" statement as in the serialized form:
{
"$set": {
"transactions.$.date_execution": new Date(),
"transactions.$.result": m_Or.getDocument()
}
}
Which is basically what you want in the end.
Your suggestion was right, just had to fix a little the syntax this way:
BasicDBObject value = new BasicDBObject();
value.put("$set",
new BasicDBObject("transactions.$.date_execution",new Date())
.append("transactions.$.result",m_OR.getDocument())
);
This worked perfectly ;)
Thanks!
Samuel
Given the JSON:
{
"_id" : 2,
"Act_Name" : "prashanth",
"Act_Alias" : "H C",
"Group_Account_Name" : "Prashan",
"OpeningBalance" : 10000,
"Dr_Cr" : 10000,
"Is_Reserved" : true,
"Is_Group_Act" : false,
"Contact_Name" : "Prashanth",
"Contact_Address" : "Bangalore",
"Cr_Limit" : 2000,
"isDeleted" : true,
"Cr_Days" : {
"BillwiseTracking" : {
"Reference_Number" : 123,
"Reference_Date" : null,
"Due_Date" : null,
"Amount" : 12334,
"Ref_Dr_Cr" : 12
}
}
}
I would like to repetitively add only the fields:
"Reference_Number" : 123,
"Reference_Date" : null,
"Due_Date" : null,
"Amount" : 12334,
"Ref_Dr_Cr" : 12
My code is follows.
BasicDBObject billwiseTracking = new BasicDBObject();
billwiseTracking.put("Reference_Number",referenceNumber);
billwiseTracking.put("Reference_Date", referenceDate);
billwiseTracking.put("Due_Date", dueDate);
billwiseTracking.put("Amount", amount);
billwiseTracking.put("Ref_Dr_Cr", refDrCr);
BasicDBObject updateObj = new BasicDBObject("BillwiseTracking", billwiseTracking);
accountHeads.update(findQuery, new BasicDBObject("$set", updateObj));
i am not properly understand your Question but if you want to append
first
"BillwiseTracking" object under "Cr_Days"
then structure should like this
"Cr_Days" :
{
"BillwiseTracking" :
[
{
"Reference_Number" : 123,
"Reference_Date" : null,
"Due_Date" : null,
"Amount" : 12334,
"Ref_Dr_Cr" : 12
},
{
"Reference_Number" : 145,
"Reference_Date" : null,
"Due_Date" : null,
"Amount" : 12355,
"Ref_Dr_Cr" : 13
}
]
}
it means it should be array element and every time you have to append for "BillwiseTracking" value
this may be your Solution
// query for append data ele.
BasicDBObject updateQuery = new BasicDBObject();
updateQuery.put( "_id", 2 );
// object to appen
BasicDBObject billwiseTracking = new BasicDBObject();
billwiseTracking.put("Reference_Number",referenceNumber);
billwiseTracking.put("Reference_Date", referenceDate);
billwiseTracking.put("Due_Date", dueDate);
billwiseTracking.put("Amount", amount);
billwiseTracking.put("Ref_Dr_Cr", refDrCr);
// push used to append data elements
BasicDBObject updateCommand = new BasicDBObject();
updateCommand.put( "$push", new BasicDBObject( "BillwiseTracking", billwiseTracking ) );
// final query execution
WriteResult result = shoppingLists.update( updateQuery, updateCommand, true, true );
I have
{
"Districts" :
[{ "name" : "Krishna"
, "Locations" : [{ "name" : "Vijayawada"}
,{ "name" : "Machilipatnam"}]}
, { "name" : "Guntur"
, "Locations" : [{ "name" : "Satenpalli"}]}
]
, "_id" : 1
, "name" : "Andhra Pradesh"
}
I am trying to create one more Location "Achampet" if District name is "Guntur" so the result should be this below. The result should be the same even if I try to add Achampet more than once.
{
"Districts" :
[{ "name" : "Krishna"
, "Locations" : [{ "name" : "Vijayawada"}
,{ "name" : "Machilipatnam"}]}
, { "name" : "Guntur"
, "Locations" : [{ "name" : "Satenpalli"}
,{ "name" : "Achampet"}]}
]
, "_id" : 1
, "name" : "Andhra Pradesh"
}
But my java code doesn't work
DBObject newLoc = new BasicDBObject("Districts", new BasicDBObject("name", distName).append("Locations", new BasicDBObject("name", locName)));
if (statesColl.findOne(newLoc) == null) {
DBObject updateLoc = new BasicDBObject("$push", newLoc);
statesColl.update(queryDist, updateLoc);
}
It is creating a new District everytime I try to add a location. How can I fix this?
This is how you can do it using the $ positional operator in Java:
...
DBObject selectQuery = new BasicDBObject("_id", 1); // Matches the document
selectQuery.append("Districts.name", distName); // Matches the element in the array where District name = Guntur
BasicDBObject updateFields = new BasicDBObject();
updateFields.put("Districts.$.Locations", new BasicDBObject("name":"Achampet"));
DBObject updateQuery = new BasicDBObject("$addToSet", updateFields);
statesColl.update(selectQuery, updateQuery);
...
My code is
DBCollection collection = db.getCollection("volume");
DBCursor cursor = collection.find();
DBObject resultElement = cursor.next();
Map resultElementMap = resultElement.toMap();
System.out.println(resultElementMap);
And the result is:
{_id=521b509d20954a0aff8d9b02, title={ "text" : "Volume Of Work
Orders" , "x" : -20.0}, xAxis={ "title" : { "text" : "2012 "} ,
"categories" : [ "Jan" , "Feb" , "Mar" , "Apr" , "May" , "Jun" , "Jul"
, "Aug" , "Sep" , "Oct" , "Nov" , "Dec"]}, yAxis={ "min" : 1000.0 ,
"max" : 7000.0 , "title" : { "text" : "Volume(K)"} , "plotLines" : [ {
"label" : { "text" : "Average" , "x" : 25.0} , "color" : "black" ,
"width" : 2.0 , "value" : 30.0 , "dashStyle" : "solid"}]}, legend={
"backgroundColor" : "#FFFFFF" , "reversed" : true}, series=[ { "name"
: "Volume" , "showInLegend" : false , "data" : [ 2909.0 , 3080.0 ,
4851.0 , 3087.0 , 2960.0 , 2911.0 , 1900.0 , 3066.0 , 3029.0 , 5207.0 , 3056.0 , 3057.0]}]}
I need to remove _id from the result. I understand i need to play around with collection.find(), but please can anyone help me? Am not able to get sesired result
Two options:
You can remove the "_id" field from the map created:
...
resultElementMap.remove("_id");
System.out.println(resultElementMap);
Or you can ask the query results to not include the _id field:
DBObject allQuery = new BasicDBObject();
DBObject removeIdProjection = new basicDBObject("_id", 0);
DBCollection collection = db.getCollection("volume");
DBCursor cursor = collection.find(allQuery, removeIdProjection);
DBObject resultElement = cursor.next();
Map resultElementMap = resultElement.toMap();
System.out.println(resultElementMap);
See the documentation on projections for all of the details.
Another option to consider, if you are reading the results iteratively, is doing something like this:
final FindIterable<Document> foundResults = collection.find();
for (final Document doc : foundResults) {
doc.remove("_id");
// doc.toJson() no longer has _id
}