How to change the type of one field in Mongoose?
For example:
var FooSchema = new Schema({
fooDate: {
type: String,
unique: true,
required: true,
trim: true
}
}
fooDate is a string type, I want to change it to Date type?
If I just change it, what will happen to the existing data? What's the proper way to migrate the old data?
Thanks.
Well it would depend on how do you have your date stored as string. Is it a valid date? Lets assume that it is either in valid ISO format or something like this:
"2019-03-20" or "2019-03-20T09:15:37.220Z"
If you simply change from String to Date mongoose would convert that for you and would treat that as the new type. So you would not need to migrate per se your date. When you get a model its fooDate would now be Date vs String before.
However the main issue you are facing now is querying data that is in two formats. Because any new records now would be saved as dates vs strings.
So you would be able to get by with the type change but while that would buy you some time you would need to migrate your data to reduce the friction during querying later. Migrating a single field would be a trivial migration script so there is nothing scary there.
PS. You can always test this btw. I just did with a simple schema and a saved record which had date as String then I updated the schema and did a simple Model.find to get that record and validate that now the date is an actual date and there was no issue with the model from mongoose. As long as the date string was in the correct date format.
You can change the data type any time .e.g
var FooSchema = new Schema({
fooDate: {
type: Date,
unique: true,
required: true,
trim: true
}
}
Now the new document records will be enter according to new data type. for existing or previous one it depends how you store a string you should make a script either in python or nodejs it depends upon you. first fetching the all records and make a helper function that take string and convert the string into data of that time you could easily do in javascript using Date Object as Date('2014-08-12')
Then you update all the previous records that you fetched in this way you can do consistency
Related
I'm trying to write to Firestore all the prices from different stocks. Structure should look something like this (although this might not be the best fitted for it, still thinking of it as in SQL) :
const d1 = new Date();
const result = d1.getTime();
console.log('Epochtime',result);
database.collection("stock1").doc("exchange1").collection(date).doc('prices').set({"price":"price_value"})
Now the problem is that I can't create a collection with a name that's a variable that contains date. I tried all the different types of it and I presumed that epoch time should work, as this is a number like: 1636213439908. I always get the error: Value for argument "collectionPath" is not a valid resource path. Path must be a non-empty string. Although the exact same variable can be written as a value in a collection. So not sure what am I doing wrong here.
Document IDs in Firestore must be strings, so you'll have to convert the data to a string. While date.toString() will work, I highly recommend using a ISO-8601 format for the dates, such as date.toISOString(). These formats are designed to be both humanly readable and machine sortable.
var curRate = nlapiCreateRecord("customrecord_currency_exchange_rates",{recordmode: 'dynamic'});
serverDt = "09/25/2013 06:00:01 am"
var timezone = compConf.getFieldText('timezone');
curRate.setDateTimeValue('custrecord_effective_date' ,serverDt ,timezone);
nlapiSubmitRecord(curRate);
Hello I try to set custrecord_effective_date field which is a date/time type. But after the execution it gives an error below.
How can I set this field?
thanks for help.
INVALID_FLD_VALUE You have entered an Invalid Field Value 09/25/2013 06:00:01 am for the following field: custrecord_effective_date
Although this is an old post and the original question is about SuiteScript 1.0, I came across this page looking for the same INVALID_FLD_VALUE error with the date/time field but in SuiteScript 2.0, and since the solution ended up being different I wanted to share it for future readers.
In SuiteScript 2.0, setting a date/time field simply requires a JavaScript date object. Below is an example within a before submit user event context.
context.newRecord.setValue({
fieldId : 'custrecord_myfield',
value : new Date()
});
For setting Date/Time Field values using SuiteScript 2.O.
First Use 'N/format' module and 'N/Record' Module.
Create a normal Javascript Date Object.
Format the Date Object to DateTime Object.
And use Record.setValue() method for setting the datetime value.
Example:
var d = new Date();
var formattedDateString = format.format({
value: d,
type: format.Type.DATETIMETZ
});
record.setValue('yourDateTimeFieldId',formattedDateString );
For anyone that may be stuck with a SuiteScript 1.0 script trying to populate a date/time field and the existing solutions don't work for you, you can try using NetSuites nlapiDateToString method. Apparently the date/time field wants a string.
Example:
var record = nlapiCreateRecord('your record type');
record .setFieldValue('your date field id', nlapiDateToString(new Date(), 'datetimetz'));
nlapiSubmitRecord(record, false, true);
The SuiteScript 1.0 reference for more detail:
Hi thanks for answers after posting the question i checked the Form of record type and when i checked for the field 'custrecord_effective_date' I noticed that the date format must be 'DD/MM/YYYY HH:MM:SS' so when i changed it worked.
If you look at the NetSuite WSDL file, you will find the dateTime declaration:
<xs:simpleType name="dateTime" id="dateTime">
<xs:documentation
source="http://www.w3.org/TR/xmlschema-2/#dateTime"/>
Go to the URL and look at the source:
3.2.7 dateTime
[Definition:] dateTime values may be viewed as objects with integer-valued year, month, day, hour and minute properties, a decimal-valued second property, and a boolean timezoned property. Each such object also has one decimal-valued method or computed property, timeOnTimeline, whose value is always a decimal number; the values are dimensioned in seconds, the integer 0 is 0001-01-01T00:00:00 ...
So the format you are looking for is:
2013-09-25T06:00:01
I just pushed a dateTime to NetSuite and it worked.
Import N/format to your script and use one of the date format types:
DATE
DATETIME
DATETIMETZ
var parsedDate = format.parse({
value: '23/12/2010',
type: format.Type.DATE
});
The code looks ok
Are there any restrictions on the date field such that you can't set a date in the past?
Also your serverDt is the same value as the Netsuite help. Did it copy cleanly? What happens if you cut that string and type it directly?
And finally are you sure you have a datetime field and not a date field. If I apply your code to a date field I get the same error.
Little addition on the existing ans.
Error type -
type: "error.SuiteScriptError",
name: "INVALID_FLD_VALUE",
message: "You have entered an Invalid Field Value 2017-07-13T08:21:12.411Z for the following field: custrecord_lastrundate",
The value need to be set as a java script date() object. Even the simple same string of js date will throw error. If you are using moment then below code will work perfectly. Sample for adding next days.
var now = moment();
now.add(1,'days')
fetchRecord.setValue({
fieldId : 'custrecord_lastrundate' ,
value : new Date(now),
ignoreFieldChange : true
});
This is related and the other 2.0 answers are correct for Date/Time fields. However I was trying to set the incident time on the case record which is just the time field, and you have to do something like this:
let incidentTime = new Date(0, 0, 0, incidentDate.getHours(), incidentDate.getMinutes());
Notice - its still a Date object, but the Y, M, D values have to be zeroed for it to work.
Ahh Netsuite - you couldn't just do that behind the scenes yourself..
Please let me know if someone has a different solution.
Not sure how to use $currentDate when inserting a document into a MongoDB collection in Meteor.
Can this only be used in an update, not an insert? Would seem strange, but I don't see an alternative (other than using new Date instead).
Example
Stuff.insert({
owner: Meteor.userId(),
createdAt: ..., // how to create this field with $currentDate ?
theStuff: "Some of the good stuff"
})
Notes / Thoughts / TL,DR
Fields can't start with $ operators or, as far as I know, curly braces {}.
What's the point of having an operator that only works with updates, if that's indeed the case?
Why/when is $currentDate better than new Date?
One nice thing, if using Moment.js esp, is that $currentDate is entered in ISO 8601 format.
Is the answer to do some kind of upsert from the start? If so, could this have unintended consequences?
What's the point of having an operator that only works with updates, if that's indeed the case?
$currentDate is an update operator thus you can't use it with the collection.insert method. But when upsert is true it will create a new document when no document matches the query criteria. MongoDB operators tend to follow the Unix philosophy
Do One Thing and Do It Well
So each operator should perform only one task.
Why/when is $currentDate better than new Date?
First I would like to mention that new Date is a JavaScript Date instance.
$currentDate and new Date can be used when you want to update the value of a field to current date but with new Date you need to use another update operator for it to work. For example:
Using new Date
db.collection.update({ "name": "bar" }, { "$set": { "date": new Date() }})
Using $currentDate
db.collection.update({ "name": "bar"},
{ "$currentDate": { "date": { "$type": date }}}
)
Unlike $currentDate, new Date can be use with the insert method and value can be set to a particular if Date is call with more than on argument.
You can retrieve timestamp from autogenerated "_id" that is created within insert operation.
http://api.mongodb.com/java/current/org/bson/types/ObjectId.html
Just use the method : ObjectId.getTimestamp().
Timestamp granularity is in seconds.
It will become more simple if you will use autoValue in collection model
createdAt:
type: Date
autoValue: ->
if this.isInsert
return new Date
else if this.isUpsert
return $setOnInsert: new Date
else
this.unset()
It will automatically set date while insert or update the data into it
$currentDate when used in the $update construct can be used to insert fields if they do not pre-exist in the document.
Quoting documentation for Mongodb 3.4:
Behavior
If the field does not exist, $currentDate adds the field to a document.
Although I do totally appreciate that this design makes perfect sense, there is an argument, perhaps a bad one, that you want to set the updated_at field to something sensible when you insert a document. One reason that you might want to do this is to avoid always needing to query on two fields to get the last updated time. Like I say, this might be bad juju, but well there you go.
Anyway the best hack that I could come up with to do this is to perform an upsert that filters on not the empty filter. That guarantees that the upsert is always an insert.
Just a small comment on this to the MongoDB Devs. As someone who has been working with databases for more years than they care to remember, getting my head around how one is supposed to do timestamps correctly in MongoDB:
created_at => _id.Timestamp
updated_at => $currentDate()
has taken me far too long. Maybe that's my fault, it probably is, but it's something that I think most people probably want / need to do and as a concept it could be explained better. If you search around you will find a lot of bad / wrong information, because I'm pretty sure that this is the way to do it and ... well the internet is far from at consensus on this (although I am now).
I don't know, maybe it's a test. Maybe this is the first thing you ask someone when you are hiring a MongoDB developer: how do you do timestamps? Well, that's what I'd ask anyway because if you know you've probably learned most of the API by that stage.
I am using Node.js to query MongoDB and have a field that is a Date (ISODate). In Node.js after querying the Date format that is returned looks like this
DT : 2014-10-02T02:36:23.354Z
What I am trying to figure out is how based on the code i have below, can efficiently convert the DT field from UTC to Local Time ISOString. In other words if local time is EDT then something like this
DT : 2014-10-02T23:36:23.354Z
I don't think there is anything I can do in the query itself from Mongo. Should I traverse the Array result set and manually change the dates? Is there a better approach here? I am sending the response to an HTTP client.
collection.find(query,options).toArray(function (err, items) {
if (err) {
logAndSendDebugError(500, "Error issuing find against mongo Employees Collection -" + type, res);
} else {
var response = {
'type': type,
'employees': items
};
res.jsonp(response);
}
});
In ES5, Date.parse should be able to parse that format, however it isn't reliable. Manually parsing it isn't hard:
// Parse ISO 8601 UTC string like 2014-10-02T23:36:23.354Z
function parseISOUTC(s) {
var b = s.split(/\D/);
return new Date(Date.UTC(b[0], --b[1], b[2], b[3], b[4], b[5], b[6]));
}
The date instance that is created will have a local timezone offset calculated from system settings. To get a UTC ISO 8601 string from a local date you can use toISOString:
var date = new Date();
console.log(date.toISOString());
Note that toISOString is ES5 so may need a polyfill if this is used in older browsers. See MDN Date.prototype.toISOString().
I would have thought the most efficient way to handle dates between the client and server would be to use the EJSON package. This covers a few things that are skirted around in other discussion here and the importance is placed on maintaining "type fidelity" when handling JSON conversion.
So what you are getting right now is the result of a "string" which is called from the "Date" object in response to a JSON.stringify call. Whatever the method being used, this is essentially what is happening where the .toJSON() method is being called from the "Date" prototype.
Rather than muck around with the prototypes or other manual processing of coversions, the EJSON package allows you to call EJSON.stringify instead which has some built in behavior to preserve types, where specifically the generated JSON string would look like this for a Date element:
{ "myCreatedDate": { "$date": 1412227831060 } }
The value there is an epoch timestamp, essentially obtained from the .valueOf() prototype method, but the field is given a special structure automagically as it were. The same is true for types other than dates as well.
The corresponding "client" processing which you can add with simple includes to your web application in the browser, e.g:
<script src="components/ejson/base64.js"></script>
<script src="components/ejson/ejson.js"></script>
This allows a same EJSON object to be present where you can process the received JSON with EJSON.parse. The resulting JavaScript Object is maintained as a "Date" type when the de-serialize is done.
var obj = EJSON.parse( "{ \"myCreatedDate\": { \"$date\": 1412227831060 } }" );
{
myCreatedDate: /* Actually a Date Object here */
}
So now in your client browser, you have a real Date object without any other processing. Any .toString() method called on that object is going to result in a value represented in a way that matches the current locale settings for that client.
So if you use this to pass the values around between server and client in a way that is going to maintain an actual "Date" object, then the correct Object values are maintained on either client and server and needs no further conversion.
Very simple to include in your project and it takes a lot of the heavy lifting of maintaining "timezone" conversions off your hands. Give it a try.
Probably worth noting that the "core" of this comes from a MongoDB specification for Extended JSON Syntax. So aside from this (partial) implementation in the EJSON package, the same "type identifiers" are supported in several MongoDB tools as well as within several driver implementations with a custom JSON parser that will automatically convert the types. Notably the Java and C# drivers have this capability shipped with the driver libraries.
It's fairly easy to follow the convention outlined in that link, and it is intended to "map" to the BSON type specifications as well. At the worst, you can always "inspect" the results from a standard JSON parser and implement custom routines to "re-instantiate" the "types". But as noted, the software is already in place with several libraries.
I have a date property coming into Breeze from my server. It looks like this in the JSON
"CreateTime":"2014-05-22T00:00:00.000"
The property is mapped in the metadata like this:
{
"name":"CreateTime",
"type":"Edm.DateTime",
"nullable":"false",
"precision":"7"
}
In the query results, however, the date always ends up as the epoch (Jan 1, 1970). However, this only happens when the entity is mapped in Breeze. If I select against the entity so that I am returning an unmapped type the date is sent across the wire identically, but it works fine.
How can I get dates to materialize correctly for mapped entities?
Using Breeze v1.4.11
Update
Here is the result of calling getEntityType on my entity:
{
"shortName":"VDisplayEvent",
"namespace":"Model",
"autoGeneratedKeyType":"None",
"defaultResourceName":"VDisplayEvents1",
"dataProperties":[
// Other properties...
{
"name":"createTime",
"dataType":"DateTime",
"isNullable":false,
"defaultValue":"1900-01-01T08:00:00.000Z",
"validators":[
{
"name":"required"
},
{
"name":"date"
}
]
},
// Other properties...
]
}
Found the problem, and it's not an issue with Breeze. My application is using a theme, which had a dependency on date.js. Apparently, date.js overrides Javascript's Date.parse() function, which is used by Breeze's DataType.parseDateAsUTC().
Date.js's Date.parse() function just returns null when confronted with parsing a date string like the one above, which was causing the issue.