How to track iteration progress using Rally's Web Services API - node.js

I am writing a custom app to track iteration progress by day. Is there a builtin way in Rally to get the number of user stories that are in the "Accepted" state for a specific date, and the number of points (or do I have to get all user stories and parse their revision histories)?

There is IterationCumulativeFlowData object in WS API, which is populated at midnight of the Workspace Timezone when the Data Collection runs on workdays specified in the Workspace Setup screen.
Data is stored for each day of the Iteration and a corresponding state. There is CumulativeFlowData object for Day 1 of the Iteration for everything in a Defined state, Day 1 of Release for everything in an In-Progress state, etc.
The CumulativeFlowData object also stores CardEstimateTotal which is the sum of the estimates of cards in every state.
Here is a example of an app written with rally-node that returns iteration data for specific state (Accepted) as of the last day of the iteration.
In this examle the CreationDate of the last result is '2013-08-27T06:00:00.000Z, while the EndDate of the iteration in question was 2013-08-27 11:59:59 PM America/Denver (which is 2013-08-28T05:59:59.000Z), so I had to manipulate a date in order to make this query condition return the data for the last day of the iteration:
query = query.and('CreationDate', '>', endDateMinusOneDay);
Here is the full js file of the example:
var rally = require('rally'),
queryUtils = rally.util.query,
restApi = rally({
user: 'user#co.com',
pass: 'secret',
apiVersion: 'v2.0',
server: 'https://rally1.rallydev.com',
requestOptions: {
headers: {
'X-RallyIntegrationName': 'My cool node.js program',
'X-RallyIntegrationVendor': 'My company',
'X-RallyIntegrationVersion': '1.0'
},
}
});
function findIteration() {
return restApi.query({
type: 'Iteration',
start: 1,
pageSize: 2,
limit: 10,
fetch: ['ObjectID', 'EndDate'],
scope: {
project: '/project/12352608219',
up: false,
down: false
},
query: queryUtils.where('Name', '=', 'i777')
});
}
function queryIterationData(result) {
var endDate = result.Results[0].EndDate,
oid = result.Results[0].ObjectID;
console.log('endDate',endDate);
var date1 = new Date(endDate);
var ms = date1.getTime() - 86400000; //86400000 is the number of milliseconds in a day
var date2 = new Date(ms);
var endDateMinusOneDay = date2.toISOString();
console.log('date2 ISO', date2.toISOString());
var query = queryUtils.where('IterationObjectID', '=',oid );
query = query.and('CardState', '=', 'Accepted');
query = query.and('CreationDate', '>', endDateMinusOneDay);
return restApi.query({
type: 'IterationCumulativeFlowData',
fetch: ['CardCount', 'CardEstimateTotal', 'CardState', 'CardState', 'CreationDate'],
query: query,
});
}
function onSuccess(result) {
console.log('Success!', result);
}
function onError(errors) {
console.log('Failure!', errors);
}
findIteration()
.then(queryIterationData)
.then(onSuccess)
.fail(onError);
It returns:

Related

Select all one day back but not older as one day

I try to use a Sequelize function to collect only table content that is older than today. But only for one day, not two days. As sample today
today: 2022/08/23
values only for: 2022/08/22 but not for 2022/08/21 and older.
For this is use:
checkDateBack: async function() {
return await dayins.findAll({
where: {
added_at: {
[Op.gte]: Sequelize.literal("DATE_SUB(CURDATE(), INTERVAL 1 DAY)"),
}
},
raw: true,
})
},
I have deleted all entries for 2022/08/22 in my temporary debug table but the result is 2022/08/21. In my idea of the function 2022/08/21 and older will get ignored.
So if I delete all entries for 2022/08/22 I expect an empty result.
Anything I did wrong with the function so it collects also 2 days old?
As I understood you need yesterday data, you need to get date range, use moment js for date
let date = new Date(); //suppose today is 2022/08/23
let endDate = moment(date).startOf("day").toString(); // starting of the day 12 am of(2022/08/23 )
let startDate = moment(date).subtract(1, "days").startOf("day").toString(); // starting of the day 12 am of(2022/08/22 )
// use [Op.between] insate of [Op.gte]
return await dayins.findAll({
where: {
added_at: {
[Op.between]: [startDate, endDate],
}
},
raw: true,
})
// it will return all data of 2022/08/22
// for sequelize createdAt if dont have any custome date fild
createdAt: {
[Op.between]: [startDate, endDate],
},

SuiteScript 2.1 record updates too slow

I have afterSubmit function that I wrote that will iterate through all related transactions connected with the same CTG_ID value (which is a custom parent record) and the script will actually update just one field on all of these values.
My problem is because this is a really slow method, more transactions I have connected to the same parent more time the user needs to wait after clicking the "Save" button. Script execution time is terrible.
Is there any faster / better way to update a certain field on a group of records?
My function for updating those transactions:
function afterSubmit(context) {
const newRecord = context.newRecord;
const ctgId = newRecord.getValue({ fieldId: 'custbody_ctgid' });
const currentCustomerPo = newRecord.getValue({ fieldId: 'custbodyctg_customer_po'})
search.create({
type: 'transaction',
filters: [['custbody_ctgid', 'anyof', ctgId],
"AND",
['mainline','is','T']],
columns: ['custbodyctg_customer_po']
}).run().getRange({start: 0, end:100}).forEach((result,line) => {
const ctgPo = result.getValue('custbodyctg_customer_po') as string;
const recType = result.recordType;
const recId = result.id;
let rec = record.load({
type: recType,
id: recId,
isDynamic: true
})
rec.setValue({
fieldId: 'custbodyctg_customer_po',
value: currentCustomerPo,
ignoreFieldChange: true
})
rec.save();
})
}
Thanks to Brian Duffy's answer, this is working a lot better!
I modified the script so now I iterate through results with each instead of forEach function. I'm using record.submitFields function instead of record.load
function afterSubmit(context) {
const newRecord = context.newRecord;
const oldRecord = context.oldRecord;
const ctgId = newRecord.getValue({fieldId: 'custbody_ctgid'});
const currentCustomerPo = newRecord.getValue({fieldId: 'custbodyctg_customer_po'})
const oldCustomerPo = oldRecord.getValue({fieldId: 'custbodyctg_customer_po'})
if (oldCustomerPo !== currentCustomerPo) {
search.create({
type: 'transaction',
filters: [['custbody_ctgid', 'anyof', ctgId],
"AND",
['mainline', 'is', 'T']],
columns: ['custbodyctg_customer_po', 'type']
}).run().each((result) => {
if (result.recordType !== 'salesorder') {
const recType = result.recordType;
const recId = result.id;
record.submitFields({
type: recType,
id: recId,
values: {
custbodyctg_customer_po: currentCustomerPo
},
options: {
enableSourcing: false,
ignoreMandatoryFields: true
}
});
}
return true;
})
}
}
Still, after testing few transactions with an average of 5 linked transactions to them this is running like 5-7 seconds. Stil slow for me. If anyone has suggestions it would be AWESOME!
I would try using run.each instead of getRange for your search results and use record.sumbitFields instead of loading and saving the record.
If speed of saving the current record is key, consider making your logic asynchronous. The current record will save nearly as fast as normal, just taking the time to schedule a Map/Reduce or Scheduled script.
The user event script would just send as parameters the current record's Id, the value in CTG_ID and the value in custbodyctg_customer_po. The asynchronous script would search for all tranx with that same Id except for the one that triggered it (or skip any records with a matching value while looping thru results), then submit the custbodyctg_customer_po for each of those.
It's a heavier solution, so you must weigh priorities.
Alternatively, look into record.submitFields.promise(options). It seems a limitation is it cannot update Select fields (ie List/Record)

Mongoose date comparison

My application will allow user to create coupons.
Coupon will be valid in datefrom and dateto period.
The thing is that every coupon should be valid for selected days, not hours.
For example since Monday(2016-06-12) to Tuesday(2016-06-13), so two days.
How should I store dates on server side and then compare it using $gte clause in Mongoose?
Thank you :-)
{ "_id" : 1, "couponStartDate" : ISODate("2016-06-26T18:57:30.012Z") }
{ "_id" : 2, "couponStartDate" : ISODate("2016-06-26T18:57:35.012Z") }
var startDate = new Date(); // I am assuming this is gonna be provided
var validDate = startDate;
var parametricDayCount = 2;
validDate.setDate(validDate.getDate()+parametricDayCount);
CouponModel.find({couponStartDate: {$gte: startDate, $lte: validDate}}, function (err, docs) { ... });
You can store expiration time as UNIX timestamp. In your Mongoose model you can use expiration : { type: Number, required: true}
If you have user interface for creating coupons then you can configure your date picker to send time in UNIX timestamp.
Or If you are getting Date string then you can use var timestamp = new Date('Your_Date_String');
And for calculation of Days you can use Moment JS. Using this you can calculate start of the date using .startOf(); and end of date using .endOf();
Timestamp return from Moment JS can be used for Mongoose query like $gte : some_timestamp and $lte : some_timestamp
If you want to validate the coupon before it is persisted, you can create a max / min value for the date field:
See this sample from official mongoose documentation on DATE validation:
var s = new Schema({ dateto: { type: Date, max: Date('2014-01-01') })
var M = db.model('M', s)
var m = new M({ dateto: Date('2014-12-08') })
m.save(function (err) {
console.error(err) // validator error
m.dateto = Date('2013-12-31');
m.save() // success
})
Hint: use snake_case or camelCase for field names

Google datastore precondition fail with timestamps

Hello I am trying to query google datastore entries from the node.js api. I have an entity which has an owner (string), a start time (date time) and an end time (date time) I am trying to query for all entities which match the given owner string and start after a given date with the following function (es2016).
static async getAvailability (owner, month = currentMonth) {
const firstOfMonth = moment([currentYear, month])
const query = datastore.createQuery('availability')
.filter('owner', '=', owner)
.filter('end', '>', firstOfMonth.toDate().toJSON())
.order('end', {
descending: true
})
try {
// promise version of run query same function
const result = await datastore.runQueryAsync(query)
return result.map(result => {
const { key, data } = result
data._id = key.id
return data
})
} catch (e) {
console.log('error', e.stack)
return []
}
}
index.yaml
indexes
- kind: availability
properties:
- name: owner
- name: start
direction: desc
- name: end
direction: desc
I am getting the error precondition failed error when i run the query. If there is any more information i can provide I would be more than happy.
Your query listed is only on owner and end. When you are using Cloud Datastore, the index you use has to exactly match the query.
In the case of the query you listed, you need the index:
- kind: availability
properties:
- name: owner
- name: end
direction: desc
If you actually wanted your start date to be a specific time, your filter would have to be:
.filter('start', '>', firstOfMonth.toDate().toJSON())
And you would have to specify it first in your orders:
.order('start')
.order('end', {
descending: true
})

MongoDB/Mongoose querying at a specific date?

Is it possible to query for a specific date ?
I found in the mongo Cookbook that we can do it for a range Querying for a Date Range
Like that :
db.posts.find({"created_on": {"$gte": start, "$lt": end}})
But is it possible for a specific date ?
This doesn't work :
db.posts.find({"created_on": new Date(2012, 7, 14) })
That should work if the dates you saved in the DB are without time (just year, month, day).
Chances are that the dates you saved were new Date(), which includes the time components. To query those times you need to create a date range that includes all moments in a day.
db.posts.find({ //query today up to tonight
created_on: {
$gte: new Date(2012, 7, 14),
$lt: new Date(2012, 7, 15)
}
})
...5+ years later, I strongly suggest using date-fns instead
import endOfDayfrom 'date-fns/endOfDay'
import startOfDay from 'date-fns/startOfDay'
MyModel.find({
createdAt: {
$gte: startOfDay(new Date()),
$lte: endOfDay(new Date())
}
})
For those of us using Moment.js
const moment = require('moment')
const today = moment().startOf('day')
MyModel.find({
createdAt: {
$gte: today.toDate(),
$lte: moment(today).endOf('day').toDate()
}
})
Important: all moments are mutable!
tomorrow = today.add(1, 'days') does not work since it also mutates today. Calling moment(today) solves that problem by implicitly cloning today.
Yeah, Date object complects date and time, so comparing it with just date value does not work.
You can simply use the $where operator to express more complex condition with Javascript boolean expression :)
db.posts.find({ '$where': 'this.created_on.toJSON().slice(0, 10) == "2012-07-14"' })
created_on is the datetime field and 2012-07-14 is the specified date.
Date should be exactly in YYYY-MM-DD format.
Note: Use $where sparingly, it has performance implications.
Have you tried:
db.posts.find({"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})
The problem you're going to run into is that dates are stored as timestamps in Mongo. So, to match a date you're asking it to match a timestamp. In your case I think you're trying to match a day (ie. from 00:00 to 23:59 on a specific date). If your dates are stored without times then you should be okay. Otherwise, try specifying your date as a range of time on the same day (ie. start=00:00, end=23:59) if gte doesn't work.
similar question
You can use following approach for API method to get results from specific day:
# [HTTP GET]
getMeals: (req, res) ->
options = {}
# eg. api/v1/meals?date=Tue+Jan+13+2015+00%3A00%3A00+GMT%2B0100+(CET)
if req.query.date?
date = new Date req.query.date
date.setHours 0, 0, 0, 0
endDate = new Date date
endDate.setHours 23, 59, 59, 59
options.date =
$lt: endDate
$gte: date
Meal.find options, (err, meals) ->
if err or not meals
handleError err, meals, res
else
res.json createJSON meals, null, 'meals'
i do it in this method and works fine
public async getDatabaseorderbyDate(req: Request, res: Response) {
const { dateQuery }: any = req.query
const date = new Date(dateQuery)
console.log(date)
const today = date.toLocaleDateString(`fr-CA`).split('/').join('-')
console.log(today)
const creationDate = {
"creationDate": {
'$gte': `${today}T00:00:00.000Z`,
'$lt': `${today}T23:59:59.999Z`
}
};
`
``
Problem I came into was filtering date in backend, when setting date to 0 hour, 0 minute, 0 second, 0 milisecond in node server it does in ISO time so current date 0 hour, 0 minute, 0 second, 0 milisecond of client may vary i.e. as a result which may gives a day after or before due to conversion of ISO time to local timezone
I fixed those by sending local time from client to server
// If client is from Asia/Kathmandu timezone it will zero time in that zone.
// Note ISODate time with zero time is not equal to above mention
const timeFromClient = new Date(new Date().setHours(0,0,0,0)).getTime()
And used this time to filter the documents by using this query
const getDateQuery = (filterBy, time) => {
const today = new Date(time);
const tomorrow = new Date(today.getDate() + 1);
switch(filterBy) {
case 'past':
return {
$exists: true,
$lt: today,
};
case 'present':
return {
$exists: true,
$gte: today,
$lt: tomorrow
};
case 'future':
return {
$exists: true,
$gte: tomorrow
};
default:
return {
$exists: true
};
};
};
const users = await UserModel.find({
expiryDate: getDateQuery('past', timeFromClient)
})
This can be done in another approach using aggregate if we have timezoneId like Asia/Kathmandu
const getDateQuery = (filterBy) => {
const today = new Date();
const tomorrow = new Date(today.getDate() + 1);
switch(filterBy) {
case 'past':
return {
$exists: true,
$lt: today,
};
case 'present':
return {
$exists: true,
$gte: today,
$lt: tomorrow
};
case 'future':
return {
$exists: true,
$gte: tomorrow
};
default:
return {
$exists: true
};
};
};
await UserModel.aggregate([
{
$addFields: {
expiryDateClientDate: {
$dateToParts: {
date: '$expiryDate',
timezone: 'Asia/Kathmandu'
}
}
},
},
{
$addFields: {
expiryDateClientDate: {
$dateFromParts: {
year: '$expiryDateClientDate.year',
month: '$expiryDateClientDate.month',
day: '$expiryDateClientDate.day'
}
}
},
},
{
$match: {
expiryDateClientDate: getDateQuery('past')
}
}
])
We had an issue relating to duplicated data in our database, with a date field having multiple values where we were meant to have 1. I thought I'd add the way we resolved the issue for reference.
We have a collection called "data" with a numeric "value" field and a date "date" field. We had a process which we thought was idempotent, but ended up adding 2 x values per day on second run:
{ "_id" : "1", "type":"x", "value":1.23, date : ISODate("2013-05-21T08:00:00Z")}
{ "_id" : "2", "type":"x", "value":1.23, date : ISODate("2013-05-21T17:00:00Z")}
We only need 1 of the 2 records, so had to resort the javascript to clean up the db. Our initial approach was going to be to iterate through the results and remove any field with a time of between 6am and 11am (all duplicates were in the morning), but during implementation, made a change. Here's the script used to fix it:
var data = db.data.find({"type" : "x"})
var found = [];
while (data.hasNext()){
var datum = data.next();
var rdate = datum.date;
// instead of the next set of conditions, we could have just used rdate.getHour() and checked if it was in the morning, but this approach was slightly better...
if (typeof found[rdate.getDate()+"-"+rdate.getMonth() + "-" + rdate.getFullYear()] !== "undefined") {
if (datum.value != found[rdate.getDate()+"-"+rdate.getMonth() + "-" + rdate.getFullYear()]) {
print("DISCREPENCY!!!: " + datum._id + " for date " + datum.date);
}
else {
print("Removing " + datum._id);
db.data.remove({ "_id": datum._id});
}
}
else {
found[rdate.getDate()+"-"+rdate.getMonth() + "-" + rdate.getFullYear()] = datum.value;
}
}
and then ran it with mongo thedatabase fixer_script.js
Well a very simple solution to this is given below
const start = new Date(2020-04-01);
start.setHours(0, 0, 0, 0);
const end = new Date(2021-04-01);
end.setHours(23, 59, 59, 999);
queryFilter.created_at={
$gte:start,
$lte:end
}
YourModel.find(queryFilter)
So, the above code simply finds the records from the given start date to the given end date.
Seemed like none of the answers worked for me. Although someone mentioned a little hint, I managed to make it work with this code below.
let endDate = startingDate
endDate = endDate + 'T23:59:59';
Model.find({dateCreated: {$gte: startingDate, $lte: endDate}})
startingDate will be the specific date you want to query with.
I preferred this solution to avoid installing moment and just to pass the startingDate like "2021-04-01" in postman.

Resources