Filter mongodb data by current month - javascript

i try to query find by month in mongodb,
my data in Daq collection is like this:
"
_id" : ObjectId("5f14081c14c08a261b816d57"),
"battery_voltage" : 3673,
"total_usage" : 0.483,
"signal" : 14,
"samplehour" : "2020-07-18T23:59:59-04:00",
"sampledate" : "2020-07-18T23:59:59-04:00",
this is my queries:
let n = moment().month()
let test = await Daq.aggregate([
{$addFields: { "month" : {$month: '$sampledate'}}},
{$match: { month: n}}
]);
i already try this too :
let n = moment().month()
let test = await Daq.aggregate([
{$project: { "month" : {$month: '$sampledate'}}},
{$match: { month: n}}
]);
but the result is always
"message": "can't convert from BSON type string to Date"
how you guys can solve this?

Your sampledate is not saved as a date object but rather as a string. You first need to convert it to a date and then you can use functions such as $month.
$addFields: {
"month": {
$month: {
$toDate: "$sampledate"
}
}
}
https://mongoplayground.net/p/XOdfYtEXqLc
I assume the fact that it's a string is actually a bug in your insert code and you should probably fix that instead.

Related

How to send parameters in request payload conditionally in reactjs and Javascript

I have below request body,
const requestbody = {
"applicationname":"app1",
"applicationtype":"permenant",
"startDate":"24 march",
"endDate":"30 march",
"refreshtime":""
}
I need to send "startDate" and "endDate" to backend only if its value is nonempty like
const requestbody = {
"applicationname":"app1",
"applicationtype":"permenant",
"startDate":"24 march",
"endDate":"30 march",
"refreshtime":"",
}
else request body should be
const requestbodywithoutdate = {
"applicationname":"app1",
"applicationtype":"permenant",
"refreshtime":30
}
The easiest way is doing something like:
const requestbody = {
"applicationname":"app1",
"applicationtype":"permenant",
...(startDate ? { startDate } : {}),
...(endDate ? { endDate } : {}),
"endDate":"30 march",
"refreshtime":"",
}
Assuming startDate is a string containing 24 march and endDate a string containing 30 march.
I used here a string as boolean, but it's up to you to replace startDate ? by somthing like values.startDate ? or other condition resulting to a boolean.
You can use lodash to exclude it.
const requestBody = _.omitBy(myObject, _.isNil)

What is the correct way of saving values into a constant in mongoose?

I have a user model and I have used timestamps in it. I need to access the createdAt date and save it in a variable. I tried
const date = await User.find({
serial: serialId,
}).select('-_id createdAt');
But this is returning
[ { createdAt: 2021-09-23T10:47:24.400Z } ]
However the only thing that i want to be saved inside my date constant is
2021-09-23T10:47:24.400Z
that also as a Date()
You are getting an array because find() returns all matches.
Get the property from the first object. Use it with the Date() constructor to get your required value as date.
Try this:
const date = await User.find({
serial: serialId,
}).select('-_id createdAt');
let finalDate = new Date(date[0].createdAt);
console.log(finalDate);
Use findOne, it returns one document. documentation of findOne : https://mongoosejs.com/docs/api.html#model_Model.findOne
const date = await User.findOne({
serial: serialId,
}, '-_id createdAt').exec();
console.log(date.createdAt)
or
const {createdAt : date}= await User.findOne({
serial: serialId,
}, '-_id createdAt').exec();
console.log(date)
const {createdAt : date} = { createdAt: '2021-09-23T10:47:24.400Z' }
console.log(date)
let fromDate = new Date(date);
console.log(fromDate.getDate())
Also look here : https://docs.mongodb.com/manual/reference/method/Date/#return-date-as-date-object

If the specific field is double, convert it to Int [duplicate]

I am trying to change the type of a field from within the mongo shell.
I am doing this...
db.meta.update(
{'fields.properties.default': { $type : 1 }},
{'fields.properties.default': { $type : 2 }}
)
But it's not working!
The only way to change the $type of the data is to perform an update on the data where the data has the correct type.
In this case, it looks like you're trying to change the $type from 1 (double) to 2 (string).
So simply load the document from the DB, perform the cast (new String(x)) and then save the document again.
If you need to do this programmatically and entirely from the shell, you can use the find(...).forEach(function(x) {}) syntax.
In response to the second comment below. Change the field bad from a number to a string in collection foo.
db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {
x.bad = new String(x.bad); // convert field to string
db.foo.save(x);
});
Convert String field to Integer:
db.db-name.find({field-name: {$exists: true}}).forEach(function(obj) {
obj.field-name = new NumberInt(obj.field-name);
db.db-name.save(obj);
});
Convert Integer field to String:
db.db-name.find({field-name: {$exists: true}}).forEach(function(obj) {
obj.field-name = "" + obj.field-name;
db.db-name.save(obj);
});
Starting Mongo 4.2, db.collection.update() can accept an aggregation pipeline, finally allowing the update of a field based on its own value:
// { a: "45", b: "x" }
// { a: 53, b: "y" }
db.collection.updateMany(
{ a : { $type: 1 } },
[{ $set: { a: { $toString: "$a" } } }]
)
// { a: "45", b: "x" }
// { a: "53", b: "y" }
The first part { a : { $type: 1 } } is the match query:
It filters which documents to update.
In this case, since we want to convert "a" to string when its value is a double, this matches elements for which "a" is of type 1 (double)).
This table provides the code representing the different possible types.
The second part [{ $set: { a: { $toString: "$a" } } }] is the update aggregation pipeline:
Note the squared brackets signifying that this update query uses an aggregation pipeline.
$set is a new aggregation operator (Mongo 4.2) which in this case modifies a field.
This can be simply read as "$set" the value of "a" to "$a" converted "$toString".
What's really new here, is being able in Mongo 4.2 to reference the document itself when updating it: the new value for "a" is based on the existing value of "$a".
Also note "$toString" which is a new aggregation operator introduced in Mongo 4.0.
In case your cast isn't from double to string, you have the choice between different conversion operators introduced in Mongo 4.0 such as $toBool, $toInt, ...
And if there isn't a dedicated converter for your targeted type, you can replace { $toString: "$a" } with a $convert operation: { $convert: { input: "$a", to: 2 } } where the value for to can be found in this table:
db.collection.updateMany(
{ a : { $type: 1 } },
[{ $set: { a: { $convert: { input: "$a", to: 2 } } } }]
)
For string to int conversion.
db.my_collection.find().forEach( function(obj) {
obj.my_value= new NumberInt(obj.my_value);
db.my_collection.save(obj);
});
For string to double conversion.
obj.my_value= parseInt(obj.my_value, 10);
For float:
obj.my_value= parseFloat(obj.my_value);
db.coll.find().forEach(function(data) {
db.coll.update({_id:data._id},{$set:{myfield:parseInt(data.myfield)}});
})
all answers so far use some version of forEach, iterating over all collection elements client-side.
However, you could use MongoDB's server-side processing by using aggregate pipeline and $out stage as :
the $out stage atomically replaces the existing collection with the
new results collection.
example:
db.documents.aggregate([
{
$project: {
_id: 1,
numberField: { $substr: ['$numberField', 0, -1] },
otherField: 1,
differentField: 1,
anotherfield: 1,
needolistAllFieldsHere: 1
},
},
{
$out: 'documents',
},
]);
To convert a field of string type to date field, you would need to iterate the cursor returned by the find() method using the forEach() method, within the loop convert the field to a Date object and then update the field using the $set operator.
Take advantage of using the Bulk API for bulk updates which offer better performance as you will be sending the operations to the server in batches of say 1000 which gives you a better performance as you are not sending every request to the server, just once in every 1000 requests.
The following demonstrates this approach, the first example uses the Bulk API available in MongoDB versions >= 2.6 and < 3.2. It updates all
the documents in the collection by changing all the created_at fields to date fields:
var bulk = db.collection.initializeUnorderedBulkOp(),
counter = 0;
db.collection.find({"created_at": {"$exists": true, "$type": 2 }}).forEach(function (doc) {
var newDate = new Date(doc.created_at);
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "created_at": newDate}
});
counter++;
if (counter % 1000 == 0) {
bulk.execute(); // Execute per 1000 operations and re-initialize every 1000 update statements
bulk = db.collection.initializeUnorderedBulkOp();
}
})
// Clean up remaining operations in queue
if (counter % 1000 != 0) { bulk.execute(); }
The next example applies to the new MongoDB version 3.2 which has since deprecated the Bulk API and provided a newer set of apis using bulkWrite():
var bulkOps = [];
db.collection.find({"created_at": {"$exists": true, "$type": 2 }}).forEach(function (doc) {
var newDate = new Date(doc.created_at);
bulkOps.push(
{
"updateOne": {
"filter": { "_id": doc._id } ,
"update": { "$set": { "created_at": newDate } }
}
}
);
})
db.collection.bulkWrite(bulkOps, { "ordered": true });
To convert int32 to string in mongo without creating an array just add "" to your number :-)
db.foo.find( { 'mynum' : { $type : 16 } } ).forEach( function (x) {
x.mynum = x.mynum + ""; // convert int32 to string
db.foo.save(x);
});
What really helped me to change the type of the object in MondoDB was just this simple line, perhaps mentioned before here...:
db.Users.find({age: {$exists: true}}).forEach(function(obj) {
obj.age = new NumberInt(obj.age);
db.Users.save(obj);
});
Users are my collection and age is the object which had a string instead of an integer (int32).
You can easily convert the string data type to numerical data type.
Don't forget to change collectionName & FieldName.
for ex : CollectionNmae : Users & FieldName : Contactno.
Try this query..
db.collectionName.find().forEach( function (x) {
x.FieldName = parseInt(x.FieldName);
db.collectionName.save(x);
});
I need to change datatype of multiple fields in the collection, so I used the following to make multiple data type changes in the collection of documents. Answer to an old question but may be helpful for others.
db.mycoll.find().forEach(function(obj) {
if (obj.hasOwnProperty('phone')) {
obj.phone = "" + obj.phone; // int or longint to string
}
if (obj.hasOwnProperty('field-name')) {
obj.field-name = new NumberInt(obj.field-name); //string to integer
}
if (obj.hasOwnProperty('cdate')) {
obj.cdate = new ISODate(obj.cdate); //string to Date
}
db.mycoll.save(obj);
});
demo change type of field mid from string to mongo objectId using mongoose
Post.find({}, {mid: 1,_id:1}).exec(function (err, doc) {
doc.map((item, key) => {
Post.findByIdAndUpdate({_id:item._id},{$set:{mid: mongoose.Types.ObjectId(item.mid)}}).exec((err,res)=>{
if(err) throw err;
reply(res);
});
});
});
Mongo ObjectId is just another example of such styles as
Number, string, boolean that hope the answer will help someone else.
I use this script in mongodb console for string to float conversions...
db.documents.find({ 'fwtweaeeba' : {$exists : true}}).forEach( function(obj) {
obj.fwtweaeeba = parseFloat( obj.fwtweaeeba );
db.documents.save(obj); } );
db.documents.find({ 'versions.0.content.fwtweaeeba' : {$exists : true}}).forEach( function(obj) {
obj.versions[0].content.fwtweaeeba = parseFloat( obj.versions[0].content.fwtweaeeba );
db.documents.save(obj); } );
db.documents.find({ 'versions.1.content.fwtweaeeba' : {$exists : true}}).forEach( function(obj) {
obj.versions[1].content.fwtweaeeba = parseFloat( obj.versions[1].content.fwtweaeeba );
db.documents.save(obj); } );
db.documents.find({ 'versions.2.content.fwtweaeeba' : {$exists : true}}).forEach( function(obj) {
obj.versions[2].content.fwtweaeeba = parseFloat( obj.versions[2].content.fwtweaeeba );
db.documents.save(obj); } );
And this one in php)))
foreach($db->documents->find(array("type" => "chair")) as $document){
$db->documents->update(
array('_id' => $document[_id]),
array(
'$set' => array(
'versions.0.content.axdducvoxb' => (float)$document['versions'][0]['content']['axdducvoxb'],
'versions.1.content.axdducvoxb' => (float)$document['versions'][1]['content']['axdducvoxb'],
'versions.2.content.axdducvoxb' => (float)$document['versions'][2]['content']['axdducvoxb'],
'axdducvoxb' => (float)$document['axdducvoxb']
)
),
array('$multi' => true)
);
}
The above answers almost worked but had a few challenges-
Problem 1: db.collection.save no longer works in MongoDB 5.x
For this, I used replaceOne().
Problem 2: new String(x.bad) was giving exponential number
I used "" + x.bad as suggested above.
My version:
let count = 0;
db.user
.find({
custID: {$type: 1},
})
.forEach(function (record) {
count++;
const actualValue = record.custID;
record.custID = "" + record.custID;
console.log(`${count}. Updating User(id:${record._id}) from old id [${actualValue}](${typeof actualValue}) to [${record.custID}](${typeof record.custID})`)
db.user.replaceOne({_id: record._id}, record);
});
And for millions of records, here are the output (for future investigation/reference)-

Query MongoDB with input form

I have a MongoDB aggregate framework that uses a startDate, endDate and intervalValue to query my database. However these variables are hardcoded. I would like to use a datepicker to send startDate, endDate and intervalValuefrom a webpage.
I initially thought I should split the JS file. One handling the request from the webpage and the other handling the GET function. Unfortunately I have reached a dead-end. I'm unable to use variables declared in sandbox.js in test.js.
Also I'm a bit confuse on how to structure my JS files to input the date and display the output.
sandbox.js
function myTime() {
var startValue = document.getElementById("startTime").value;
var endValue = document.getElementById("endTime").value;
var intervalValue = document.getElementById("interval").value;
var startDate = new Date("1/1/2015 " + startValue);
var endDate = new Date("1/1/2015 " + endValue);
var offset = intervalValue * 1000 * 60;
}
test.js
{ $match : { datetime : { $gt : startDate, $lt : endDate } } },
{
$group: {
_id:{
"$add": [
{ "$subtract": [
{ "$subtract": [ "$datetime", new Date(0) ] },
{ "$mod": [
{ "$subtract": ["$datetime" , new Date(0) ] },
offset]}] },
new Date(0)
]},
Humidity: {$avg: "$humidity"},
Temperature: {$avg: "$temperature"}
},
},
{ $project : { _id : 1 , Humidity : 1, Temperature: 1 } },
// { $limit : 10 },
{ $sort : {"_id":1, "Humidity":1, "Temperature": 1}}
I will be glad if I can get some help. Thanks
Firstly, you need to make sure that both files are included in the HTML page that you are loading (i.e. your form).
Next, I see that your test.js file is simply a JSON object.
I would recommend changing this so that you return a JSON object via a function call rather. This will allow you to pass through your gathered inputs into the function to return your required JSON object to send to Mongo.
I would recommend giving the following changes a try:
sandbox.js changes
function myTime() {
var result = {}
result.startValue = document.getElementById("startTime").value;
result.endValue = document.getElementById("endTime").value;
result.intervalValue = document.getElementById("interval").value;
result.startDate = new Date("1/1/2015 " + startValue);
result.endDate = new Date("1/1/2015 " + endValue);
result.offset = intervalValue * 1000 * 60;
return result;
}
This will allow you get get all the variables into a result to pass through to the test.js file
test.js changes
function getMongoObject(values) {
return { "$match" : { "datetime" : { "$gt" : values.startDate, "$lt" : values.endDate } } },
{
"$group": {
"_id":{
"$add": [
{ "$subtract": [
{ "$subtract": [ "$datetime", new Date(0) ] },
{ "$mod": [
{ "$subtract": ["$datetime" , new Date(0) ] },
values.offset]}] },
new Date(0)
]},
"Humidity": {$avg: "$humidity"},
"Temperature": {$avg: "$temperature"}
},
},
{ "$project" : { "_id" : 1 , "Humidity" : 1, "Temperature": 1 } },
// { "$limit" : 10 },
{ "$sort" : {"_id":1, "Humidity":1, "Temperature": 1}}
}
Once you've made those changes to the test.js file, you can execute the following where you want to get the JSON object to pass to Mongo.
var mongoValues = getTime();
var mongoObject = getMongoObject(mongoValues);
Now you can use mongoObject to send to the DB.
UPDATE:
Approach 2:
If you do not want to send the variables through to the test.js file you will need to make your variables in the sandbox.js file global. Currently they are "private" (scoped only to the function)
Try these changes to sandbox.js
var startValue, endValue, intervalValue, startDate, endDate, offset;
function myTime() {
startValue = document.getElementById("startTime").value;
endValue = document.getElementById("endTime").value;
intervalValue = document.getElementById("interval").value;
startDate = new Date("1/1/2015 " + startValue);
endDate = new Date("1/1/2015 " + endValue);
offset = intervalValue * 1000 * 60;
}
In my opinion, option 1 is still better because it allows you to control what the variables are that you are binding to your JSON object that you will be passing to Mongo.
With this method, you could accidentally get different results in your JSON object due to the variables not being set at the time test.js is invoked or due to the variables being accidentally overridden.
UPDATE 3
In order to access the startDate and other variables in the test.js file you will need to make the JSON object a variable.
I have made a github repo for a test to show you want I mean, check it out here:
https://github.com/NewteqDeveloper/so-q-41462690
From this example you will note that the alert displays 2. (startdate + 1).
For more information check this stackoverflow page: Can I access variables from another file?.
An important note to make is that you need to include the sandbox.js file before the test.js file in the html page.

MongoDB select where in array of _id?

is possible in mongo db to select collection's documents like in SQL :
SELECT * FROM collection WHERE _id IN (1,2,3,4);
or if i have a _id array i must select one by one and then recompose the array/object of results?
Easy :)
db.collection.find( { _id : { $in : [1,2,3,4] } } );
taken from: https://www.mongodb.com/docs/manual/reference/operator/query/in/#mongodb-query-op.-in
Because mongodb uses bson and for bson is important attribute types. and because _id is ObjectId you must use like this:
db.collection.find( { _id : { $in : [ObjectId('1'),ObjectId('2')] } } );
and in mongodb compass use like this:
{ "_id" : { $in : [ObjectId('1'),ObjectId('2')] } }
Note: objectId in string has 24 length.
You can try this
var ids = ["5883d387971bb840b7399130","5883d389971bb840b7399131","5883d38a971bb840b7399132"];
var oids = [];
ids.forEach(function(item){
oids.push(new ObjectId(item));
});
.find({ _id: {$in : oids}})
In this code list is the array of ids in user collection
var list = ["5883d387971bb840b7399130","5883d389971bb840b7399131","5883d38a971bb840b7399132"]
.find({ _id: {$in : list}})
if you want to find by user and also by another field like conditionally, you can easily do it like beneath with spread and ternary operator using aggregate and match
const p_id = patient_id;
let fetchingReports = await Reports.aggregate([
...(p_id
? [
{
$match: {
createdBy: mongoose.Types.ObjectId(id),
patient_id: p_id,
},
},
]
: [
{
$match: {
createdBy: mongoose.Types.ObjectId(id),
},
},

Categories