Creating a variable in nested mongodb document - mongodb

_id : { name : xyz,
Rollnumber : 123}
Stats : [ { subject : Maths,
Examdate : 2020-08-24 },
{ Subject : English,
Examdate : 2020-08-24} ]
I've a mongodb document like this :
To extract the name and roll number in a variable I can do like:
Var a = _id.name;
Var b = _id.rollnumber;
I want to extract the Examdate field in a variable , they can be multiples within one document.
Var c = Stats.Examdate;
It's returning unknown type error,
I've to use these three variables in a cursor, is there any way to achieve it .

Related

GET a string inside a object nested within a array

I have a get router that gets orders with the time stamp
router.get('/api/order/:date/:time', function (req,res,next) {
Box.find({orders: {date:req.params.date}}.then (function (order){
console.log('GET ORDER / with ', req.params.date);
res.send(order);
}).catch(next);
});
the :time is just to allow my frontend to call this specific get which offers a timestamp inside the :date parameter
now, the model
const orderSchema = new Schema({
name : { type : String },
date : { type : String }, // date stamp of only YYYY/MM/DD
orders : { type : Array}
});
Inside this array of orders you can find elements such as:
"orders" : [
{
"type" : "Meat Lover Slice",
"extraType" : "na",
"extraInfo" : "na",
"date" : "2018-09-27:08:47:07",
"quantity" : "1",
"size" : "medium",
"crust" : "normal",
"split" : false,
and so on.. (15 or so elements)
You can see inside this array of orders, there are time stamped with YYYY/MM/DD:HH:MM:SS (2018-09-27:08:47:07).
inside the router, I do get
console.log('GET ORDER / with ', req.params.date) // > GET ORDER / with 2018-09-27:08:47:07
so it does receive the time at this route.
But with the params, how do I filter out the the specific orders matching that element?
If I have understood the question correctly is the short answer is that you can't, there is no way to "filter" sub-documents in a standard query. (Have a look at Return only matched sub-document elements within a nested array for a more in depth answer.)
What you could do is either use MongoDB Aggregations (https://docs.mongodb.com/manual/aggregation/) or do the filtering yourself when you have received the query result.
I would suggest doing the filtering yourself.

Getting distinct values from object array MongoDB

{
"_id" : NUUID("f5050a5d-b3be-4de6-a135-a119436fb511"),
"CoursesData" : [
{
"Name" : "Naturgræs",
"Value" : 1
}
],
"FacilityType" : {
"_id" : NUUID("a1b4844b-518b-40e2-8aa5-8ee399ac2d4e")
}
}
I want to retrieve a list with the distinct values from the field Name inside my object array of CourseData. Filtered by FacilityType._id. I tried using both $facet and the distinct operator, but it doesn't seems to like object arrays.
My result should look like this (or similar):
FacilityType (a1b4844b-518b-40e2-8aa5-8ee399ac2d4e),
CourseData: [Name1, Name2, Name3]
Update
From the answer given below, this is how you do it with the C# driver, if anyone needs to do the same.
FieldDefinition<FacilityDocument, string> field = "CoursesData.Name";
var result = FacilityCollection.Distinct(field, Builders<FacilityDocument>.Filter.Eq(x => x.FacilityType.ID, new Guid("a1b4844b-518b-40e2-8aa5-8ee399ac2d4e"))).ToList();
You can use distinct(). It will return distinct element for a specific field from document which match a query
For example if you want distinct value of Name field for facility "a1b4844b-518b-40e2-8aa5-8ee399ac2d4e", run this query:
db.collection.distinct("CoursesData.Name", {"FacilityType._id": "a1b4844b-518b-40e2-8aa5-8ee39ac2d4e"})
it will return :
[ "Naturgræs", ... ]

Searching with dynamic field name in MongoDB

I have a situation where records in Mongo DB are like :
{
"_id" : "xxxx",
"_class" : "xxxx",
"orgId" : xxx,
"targetKeyToOrgIdMap" : {
"46784_56139542ecaa34c13ba9e314" : 46784,
"47530_562f1bc5fc1c1831d38d1900" : 47530,
"700004280_56c18369fc1cde1e2a017afc" : 700004280
},
}
I have to find out the records where child nodes of targetKeyToOrgIdMap has a particular set of values. That means, I know what the value is going to be there in the record in "46784_56139542ecaa34c13ba9e314" : 46784 part. And the field name is variable, its combination of the value and some random string.
In above example, I have 46784, and I need to find all the records which have 46784 in that respective field.
Is there any way I can fire some regex or something like that or by using any other mean where I would get the records which has the value I need in the child nodes of the field targetKeyToOrgIdMap.
Thanks in advance
You could use MongoDB's $where like this:
db.myCollection.find( { $where: function() {
for (var key in obj.targetKeyToOrgIdMap) {
if (obj.targetKeyToOrgIdMap[key] == 46784){
return true;
}
}
}}).each { obj ->
println obj
}
But be aware that this will require a full table scan where the function is executed for each document. See documentation.

MongoDB: Setting in a document with a nested document with nested arrays with nested documents

I want to $set a field in all documents within all arrays within a document within a document.
Basically, I want to do this
{$set : {'documentname.*anyandallstrings*.*anyandallnum*.fieldname' : value}}
A sample of the document schema is here
{
"_id" : "abc123",
"documenttoset" : {
"arrayname" : [
{
"fieldname" : "fieldvalue"
//i want to add fields here,
},
{
"fieldname2" : "fieldvalue2",
"fieldname3" : "fieldvalue3"
//here,
}
],
"arrayname2" : [
{
"fieldname4" : "fieldvalue4",
"fieldname5" : "fieldvalue5",
"fieldname6" : "fieldvalue6",
//and here.
}
]
},
}
It should add the field in question to these nested documents, and must be scalable if there are more documents and more arrays.
I did not design the schema.
How is this done? I am not sure if it is even possible.
The only way to accomplish this is to iterate through the documents and update each field individually.
import pymongo
c = pymongo.mongo_client.MongoClient(host='localhost')
db = c.local
cursor = db.test.find()
for q in cursor:
dic = q
for f in dic:
field = dic[f]
if(f != '_id'):
for a in field:
array = field[a]
for d in array:
d['newfield'] = 'value'
After you've done that you just have to find the document in question and update it.
db.test.update({'_id':'abc123'}, dic)
You'll have to use a driver (obviously). I like using python and pymongo, but there are tons of drivers out there.
If this is a db admin job I would recommend using pymongo within the python shell.
Hope it helps!!

Can the field names in a MongoDB document be queried, perhaps using aggregation?

In this article from the MongoDB blog, "Schema Design for Time Series Data in MongoDB" the author proposed storing multiple time series values in a single document as numbered children of a base timestamp (i.e. document per minute, seconds as array of values).
{
timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"),
type: “memory_used”,
values: {
0: 999999,
…
37: 1000000,
38: 1500000,
…
59: 2000000
}
}
The proposed schema sounds like a good one but they fail to mention how to query the "values" field names which would be required if you wanted to know when the last sample occurred.
How would you go about constructing a query to find something like the time of the most recent metric (combining timestamp_minute and highest field name in the values)?
Thanks so much!
You can just query the minute document and then use a loop on the client to
determine which timestamps have been set:
doc = c.find(...)
var last = 0
for (var i=0; i<60; i++)
if (i in doc.values)
last = i
Another approach which is a little more efficient is to use an array
instead of a document for the per-second samples, and then use the
length of the array to determine how many second samples have been
stored:
doc = c.find(...)
last = doc.values.length - 1
I found the answer "can the field names be queried" in another blog post which showed iterating over the keys (as Bruce suggests) only doing so in a MapReduce function ala:
var d = 0;
for (var key in this.values)
d = Math.max(d, parseInt(key));
For the MMS example schema (swapping in month for timestamp_minute and days in the values array labeled v below) here is the data and a query that produces the most recent metric date:
db.metricdata.find();
/* 0 */
{
"_id" : ObjectId("5277e223be9974e8415f66f6"),
"month" : ISODate("2013-10-01T04:00:00.000Z"),
"type" : "ga-pv",
"v" : {
"10" : 57,
"11" : 49,
"12" : 91,
"13" : 27,
...
}
}
/* 1 */
{
"_id" : ObjectId("5277e223be9974e8415f66f7"),
"month" : ISODate("2013-11-01T04:00:00.000Z"),
"type" : "ga-pv",
"v" : {
"1" : 145,
"2" : 51,
"3" : 63,
"4" : 29
}
}
And the map reduce function:
db.metricdata.mapReduce(
function() {
var y = this.month.getFullYear();
var m = this.month.getMonth();
var d = 0;
// Here is where the field names used
for (var key in this.v)
d = Math.max(d, parseInt(key));
emit(this._id, new Date(y,m,d));
},
function(key, val)
{
return null;
},
{out: "idandlastday"}
).find().sort({ value:-1}).limit(1)
This produces something like
/* 0 */
{
"_id" : ObjectId("5277e223be9974e8415f66f7"),
"value" : ISODate("2013-11-04T05:00:00.000Z")
}