Mongo DB : Impact of object schema changes on document design - mongodb

How do you handle schema changes in Mongo db e.g. say after refactoring you change your object schema design and that impacts the document schema. Is there a way to update the document schema?

You can run an update on the entire schema, removing fields, or adding fields and setting them to calculated values, if that's what you're getting at.
Say you had an x field, and you want to add a y field that should be set to x/2, you could do something like this:
PRIMARY> db.test.insert({x:15});
PRIMARY> db.test.insert({x:30});
PRIMARY> db.test.insert({x:50});
PRIMARY> db.test.find();
{ "_id" : ObjectId("4f9df1ebed2b924eedb8cad9"), "x" : 15 }
{ "_id" : ObjectId("4f9df1eeed2b924eedb8cada"), "x" : 30 }
{ "_id" : ObjectId("4f9df1f1ed2b924eedb8cadb"), "x" : 50 }
PRIMARY> db.test.find().forEach(function(doc) {
doc.y = doc.x/2;
db.test.save(doc);
});
PRIMARY> db.test.find();
{ "_id" : ObjectId("4f9df1ebed2b924eedb8cad9"), "x" : 15, "y" : 7.5 }
{ "_id" : ObjectId("4f9df1eeed2b924eedb8cada"), "x" : 30, "y" : 15 }
{ "_id" : ObjectId("4f9df1f1ed2b924eedb8cadb"), "x" : 50, "y" : 25 }

Related

Mongo query to find documents which have date less than a particular date and delete it

So this is my data in mongodb
{
"_id" : ObjectId("60f67dc955784b233692a0f2"),
"Id" : "9153",
"InfoList" : [
{
"itemId" : "42342",
"price" : 1009.0,
"date" : ISODate("2021-01-01T08:30:36.131Z")
}
]
}
{
"_id" : ObjectId("6105668a55784bd00ef3ebc6"),
"Id" : "894249",
"InfoList" : [
{
"itemId" : "42342",
"price" : 23.0,
"date" : ISODate("2021-01-01T08:30:36.131Z")
},
{
"itemId" : "3221",
"price" : 44554.0,
"date" : ISODate("2013-07-31T15:05:10.042Z")
}
]
}
I want to find all the items in InfoList for all the documents whose date is less than 2021-02-09 and then delete them.
This is the code that I am using
Query query = new Query();
query.addCriteria(Criteria.where("InfoList")
.elemMatch(Criteria
.where("date")
.lte(date)));
return mongoTemplate.findAllAndRemove(query,ProductInfo.class, CollectionName);
But this code is neither finding the documents which have date < 2021-02-01 nor deleting them. Any suggestions regarding what might be wrong here ?
I'm not familiar with Mongo query I know mongoose more
But do it like this 1-get all the of the object
It will return an array
On this array
2-do an if to check if the date is less than 2021-02-09 if yes remove it using its id

Insert document into mongodb from existing table

I am trying to write a query in mongo that will create a new table, loop through my data set, and insert the TopExecutiveTitle into the new table. I also would like it to keep count of each position and only insert a position into the table when it is new.
This is what I have so far. This code loops through my table and inserts the TopExectuiveTitle into a new table. However, it does not group them together and keep count. How do I write my query so that it will?
db.car.find().forEach( function (x) {
db.TopExecutiveTable.insert({Topexecutivetitle: x.Topexecutivetitle})
});
Here is a sample of a document in my database.
{
"_id" : ObjectId("5a22c8e562c2e489c5df70fa"),
"2016rank" : 1,
"Dealershipgroupname" : "AutoNation Inc.?",
"Address" : "200 S.W. 1st Ave.",
"City/State/Zip" : "Fort Lauderdale, FL 33301",
"Phone" : "(954) 769-7000",
"Companywebsite" : "www.autonation.com",
"Topexecutive" : "Mike Jackson",
"Topexecutivetitle" : "chairman & CEO",
"Totalnewretailunits" : "337,622",
"Totalusedunits" : "225,713",
"Totalfleetunits" : 3,
"Totalwholesaleunits" : "82,342",
"Total_units" : "649,415",
"Total_number_of _dealerships" : 260,
"Grouprevenuealldepartments*" : "$21,609,000,000",
"2015rank" : 1
}
The result I would like is something like this
"Topexecutivetitle" : "chairman & CEO"
"Count" : 3
"Topexecutivetitle" : "president"
"Count" : 7
}
To do this you need to use the aggregate function of mongo, something like this:
db.car.aggregate([
{
$group:{
_id:"$Topexecutivetitle",
count:{$sum:1}
}
},
{
$project:{
Topexecutivetitle:"$_id",
count:1,
_id:0
}
},
{
$out:"result"
}])
This will give you your desired output and store it into a new collection "result":
{
"_id" : "president",
"count" : 1.0
},
{
"_id" : "chairman & CEO",
"count" : 3.0
}

How to get all subfields of mongodb in a query when one field is root field of other field requested?

For this specific case, everything works fine, except when
for the fields field1,field2 requested, and field1 is a part of field2.
Example :
> db.mycoll.findOne()
{
"_id" : 1,
"data" : {
"amounts" : {
"dollar" : 20,
"euro" : 18
},
"item" : "toy",
"sale" : false
}
}
// works well
> db.mycoll.findOne({"_id":1},{ "data.amounts.dollar":1 })
{ "_id" : 1, "data" : { "amounts" : { "dollar" : 20 } } }
// here "data" is root of "data.amounts.dollar" and "data.amounts.euro"
// takes preference, how to query for "data", so
// that all subfields of data are
// returned
> db.mycoll.findOne({"_id":1},{ "data":1 , "data.amounts.dollar":1 })
{ "_id" : 1, "data" : { "amounts" : { "dollar" : 20 } } }
Expected output :
{
"_id" : 1,
"data" : {
"amounts" : {
"dollar" : 20,
"euro" : 18
},
"item" : "toy",
"sale" : false
}
}
Yes, it is possible to format the subfields on the program side, and send the root field to mongodb query, but my question is if this is feasible on the querying side without Javascript .
This is unusual behavior, a bug to be precise.
From credible/official sources :
Jira Open Bug
Jira Bug Duplicate
Seems that the bug is still open.
Please let me know if you need any further analysis.
db.mycoll.findOne({"_id":1},{"data.amounts.dollar":1,"data":1 })
This gives as expected result
db.getCollection(coll_name).find({_id:1},{data:1});
This will give output
{
"_id" : 1,
"data" : {
"amounts" : {
"dollar" : 20,
"euro" : 18
},
"item" : "toy",
"sale" : false
}
}
Once you use a projection (the second json document in the 'find()', only those fields specified in the projection will be returned by the server (The exception is '_id' which will be returned unless explicitly turned off by _id:0).
{ "data":1 , "data.amounts.dollar":1 }
By selecting data.amounts.dollar inside the sub-document, you have essentially turned off the other members of the data.amounts document.
You can turn them on like you did with dollar, but I think you want them all projected regardless of knowing or not the field names.
I could not find in the documentation anything about order of fields in the projection field.
From the Mongo Documentation here
https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/#projection-document

MongoDB Remove All Rows with a Certain Field

How can I remove all rows/records/entries that have a certain property set in MongoDB? For example, how can I remove all the rows that have an x field without removing the last row, which has no x field?
{ "_id" : ObjectId("53907a0adf55a0a97263b36d"), "x" : 21 }
{ "_id" : ObjectId("53907a0adf55a0a97263b36e"), "x" : 22 }
{ "_id" : ObjectId("53907a0adf55a0a97263b36f"), "x" : 23 }
{ "_id" : ObjectId("53907a0adf55a0a97263b370"), "x" : 24 }
{ "_id" : ObjectId("53907a16df55a0a97263b372"), "name" : "Bob" }
I tried this, but it removed everything:
db.testData.remove({}, {x:""})
http://docs.mongodb.org/manual/reference/operator/query/exists/
db.testData.remove({x: {$exists: true}})

mongodb get elements which was inserted after some document

I have a document and I need to query mongodb database to return me all the documents which was inserted after current document.
Is it possible and how to do that query?
If you do not override the default _id field you can use that objectID (see the mongodb docs) to make a comparison by time. For instance, the following query will find all the documents that are inserted after curDoc has been inserted (assuming none overwrite the _id field):
>db.test.find({ _id : {$gt : curDoc._id}})
Note that these timestamps are not super granular, if you would like a finer grained view of the time that documents are inserted I encourage you to add your own timestamp field to the documents you are inserting and use that field to make such queries.
If you are using Insert time stamp as on of the parameter, you can query like below
> db.foo.find()
{ "_id" : ObjectId("514bf8bbbe11e483111af213"), "Name" : "abc", "Insert_time" : ISODate("2013-03-22T06:22:51.422Z") }
{ "_id" : ObjectId("514bf8c5be11e483111af214"), "Name" : "xyz", "Insert_time" : ISODate("2013-03-22T06:23:01.310Z") }
{ "_id" : ObjectId("514bf8cebe11e483111af215"), "Name" : "pqr", "Insert_time" : ISODate("2013-03-22T06:23:10.006Z") }
{ "_id" : ObjectId("514bf8eabe11e483111af216"), "Name" : "ijk", "Insert_time" : ISODate("2013-03-22T06:23:38.410Z") }
>
Here my Insert_time corresponds to the document inserted time, and following query will give you the documents after a particular Insert_time,
> db.foo.find({Insert_time:{$gt:ISODate("2013-03-22T06:22:51.422Z")}})
{ "_id" : ObjectId("514bf8c5be11e483111af214"), "Name" : "xyz", "Insert_time" : ISODate("2013-03-22T06:23:01.310Z") }
{ "_id" : ObjectId("514bf8cebe11e483111af215"), "Name" : "pqr", "Insert_time" : ISODate("2013-03-22T06:23:10.006Z") }
{ "_id" : ObjectId("514bf8eabe11e483111af216"), "Name" : "ijk", "Insert_time" : ISODate("2013-03-22T06:23:38.410Z") }
>