Powershell Split PSCustomObject if Property has multiple values while duplicating other values - powershell

My current PSCustomObject
Invoice
Auction
Item ID
Date
18585208
X8C3E5651
K5W6L07795
Feb 18, 2021
99457377
U9V7E3466
J2X1D40777
Feb 14, 2022
91833688
D2A7O0545
T7Z6Y74627,H3B4U81837
Feb 23, 2021
76058226
K3N0T6688
G1D0B37486,Q3B8Z87471
Aug 21, 2021
65314754
C1C1F6626
Q8D2J82095
Dec 9, 2021
Rows 3 and 4 have multiple Item ID's which need to be split into their own rows but with the Invoice, Auction, and Date properties duplicated to match.
Intended output:
Invoice
Auction
Item ID
Date
18585208
X8C3E5651
K5W6L07795
Feb 18, 2021
99457377
U9V7E3466
J2X1D40777
Feb 14, 2022
91833688
D2A7O0545
T7Z6Y74627
Feb 23, 2021
91833688
D2A7O0545
H3B4U81837
Feb 23, 2021
76058226
K3N0T6688
G1D0B37486
Aug 21, 2021
76058226
K3N0T6688
Q3B8Z87471
Aug 21, 2021
65314754
C1C1F6626
Q8D2J82095
Dec 9, 2021
After a ton of research, I've tried multiple things but the logic is getting lost on me. I can select by property name and split each but have trouble on the new line portion.
My Object code:
$data = foreach ($foo in $AllMatches)
{
[PSCustomObject]#{
'Invoice' = ($data.Groups.Where{$_.Name -like 'Invoice'}).Value
'Auction' = ($data.Groups.Where{$_.Name -like 'Auction'}).Value
'Items' = ($data.Groups.Where{$_.Name -like 'Items'}).Value
'Date' = ($data.Groups.Where{$_.Name -like 'Date'}).Value
}
}

Your code is a bit unclear, but if you already have an array of PsObjects and need to split on a certain property, here's one way of doing that.
For demo, I'm using your example data as Here-String and convert that from CSV:
$dataToSplit = #"
Invoice Auction Item ID Date
18585208 X8C3E5651 K5W6L07795 Feb 18, 2021
99457377 U9V7E3466 J2X1D40777 Feb 14, 2022
91833688 D2A7O0545 T7Z6Y74627,H3B4U81837 Feb 23, 2021
76058226 K3N0T6688 G1D0B37486,Q3B8Z87471 Aug 21, 2021
65314754 C1C1F6626 Q8D2J82095 Dec 9, 2021
"# | ConvertFrom-Csv -Delimiter "`t"
$data = foreach ($item in $dataToSplit) {
$item.'Item ID' -split ',' | ForEach-Object {
[PSCustomObject]#{
'Invoice' = $item.Invoice
'Auction' = $item.Auction
'Item ID' = $_
'Date' = $item.Date
}
}
}
$data
Output:
Invoice Auction Item ID Date
------- ------- ------- ----
18585208 X8C3E5651 K5W6L07795 Feb 18, 2021
99457377 U9V7E3466 J2X1D40777 Feb 14, 2022
91833688 D2A7O0545 T7Z6Y74627 Feb 23, 2021
91833688 D2A7O0545 H3B4U81837 Feb 23, 2021
76058226 K3N0T6688 G1D0B37486 Aug 21, 2021
76058226 K3N0T6688 Q3B8Z87471 Aug 21, 2021
65314754 C1C1F6626 Q8D2J82095 Dec 9, 2021

Here you have an example of how you can do it, the following iterates over each object of the array and splits by comma the value of Item ID, if result is one elements it returns the element as is, else, it will iterate over the elements of splitting and update a copy of the row the current row.
foreach($obj in $array) {
if(($items = $obj.'Item ID'.Split(',')).Count -eq 1) {
$obj
continue
}
foreach($item in $items) {
$i = $obj.PSObject.Copy()
$i.'Item ID' = $item
$i
}
}

Related

Get last business day factoring in holidays in Powershell

I have the following Powershell script that works fine to get the last business/working days, however I am trying to factor in (US) holidays. Can that be done by improving the following script?
$DateOffset = If ((get-date).dayofweek.value__ -eq 1) {-3} Else {-1}
You could do something like this:
function Get-LastBusinessDay {
[CmdletBinding()]
param (
[Parameter(Position = 1)]
[System.DateTime]$Date = [System.DateTime]::Today,
[Parameter(Position = 2)]
[System.DateTime[]]$Holidays
);
$Weekends = #([System.DayOfWeek]::Saturday, [System.DayOfWeek]::Sunday);
$LastBusinessDay = $Date.AddDays(-1);
while (($LastBusinessDay.DayOfWeek -in $Weekends) -or ($LastBusinessDay.Date -in $Holidays)) {
$LastBusinessDay = $LastBusinessDay.AddDays(-1);
}
return $LastBusinessDay;
}
$HolidayTable = #(
# 2018 US Federal Holidays
'January 1, 2018',
'January 15, 2018',
'February 19, 2018',
'May 28, 2018',
'July 4, 2018',
'September 3, 2018',
'October 8, 2018',
'November 12, 2018',
'November 22, 2018',
'December 25, 2018'
);
Get-LastBusinessDay -Date '2018-12-26' -Holidays $HolidayTable
# Returns December 24
Get-LastBusinessDay -Date '2018-09-04' -Holidays $HolidayTable
# Returns Aug 31
The list of holidays can come from anywhere.
Holidays can be difficult to work with when calculating workdays. I use a script from Alan Kaplan that pulls holidays from TimeAndDate.com for any year and any country as PowerShell object.
With that, it should be easy to adjust the calculation as needed.
#Example. Get US National Holidays for 2015, display in two columns with Holiday and Date with day.
$holidays =Get-Holidays 2015
#$holidays now is an object with the holidays for 2015, which you can manipulate
$holidays | where {$_.type -like "National Holiday"} |
select #{Name="Holiday"; Expression = {$_.holidayName}}, #{Name="Date"; Expression = {Get-Date($_.date) -format D}} |
ft -AutoSize

find results not matching date in selector

A Meteor client Template returns mongodb cursor. The collection has 3 documents which contain date field. I expected the find to return 3 documents, but it only gave one the date of which is Mon Aug 08 2016 00:00:00 GMT+1000 (AEST).
Why is that and how can I get the 3 documents? Thanks
"date" : ISODate("2016-08-08T14:00:00Z"),
"date" : ISODate("2016-08-08T14:00:00Z"),
"date" : ISODate("2016-08-07T14:00:00Z"),
console.log(start); //=> Sun Aug 07 2016 00:00:00 GMT+1000 (AEST)
console.log(end); //=> Mon Aug 08 2016 00:00:00 GMT+1000 (AEST)
console.log(myCol.find({date: {$gte: start, $lte: end}}).fetch()); // expected 3 not just 1
the code below shows how the date was before inserting in the collection.
const date = cheerioObj(this).next().html().trim();
const dArr = date.split('/');
const dObj = new Date(parseInt(dArr[2]), parseInt(dArr[1]) - 1, parseInt(dArr[0]));
EDIT: Sorry, it's late.
It may be to do with your .fetch() method. Try iterating the cursor instead:
var myArray = db.users.find({...}).toArray();
Then access each in a for loop.

How to format a date in Ext JS 3?

I have a date value like this ;
Date {Fri Feb 13 2015 02:00:00 GMT+0200 (GTB Standart Saati)}
I get it from a grid column with ;
selectionModel.getSelected().data['date'];
And column model date format is 'd/m/Y'. It shows in grid well (d/m/Y).But when i get selected value it returns a date format doesn't like 'd/m/Y'. How can i format this date to set to a textfield ?
According to ExtJs Docs
var d = new Date(1993, 6, 28, 14, 39, 7);
println(d.toString()); // prints Wed Jul 28 1993 14:39:07 GMT-0600 (PDT)
println(d.toDateString()); // prints Wed Jul 28 1993
Edit:
Please use Ext.Date.format to format the date:
Ext.Date.format(d,'d/m/Y');
According to ExtJS 3.4 Docs Date object is extended with .format() method.
So you should be able to just do
var d = new Date();
d.format("d/m/Y");

MongoDB row index limit query like SQL

I would like to retrieve a list that contains an specified record under some conditions and only retrieve a number of records before and a number of records after that record. Are there any solutions?
For example, I have a MongoDB schema { id, date, section }
Data set:
100, 26 Aug 2014 11:00, A
110, 26 Aug 2014 11:01, A
140, 26 Aug 2014 12:00, A
141, 27 Aug 2014 12:00, B
200, 30 Aug 2014 11:00, A
210, 01 Sep 2014 11:01, B
290, 02 Sep 2014 12:00, A
300, 26 Sep 2014 12:00, A
301, 27 Oct 2014 12:00, B
302, 30 Oct 2014 11:23, A
410, 01 Oct 2014 15:01, B
590, 02 Oct 2014 12:00, A
600, 26 Nov 2014 00:00, A
I would like to get a list, which contains an unique id = 300 and 3 records before and 3 records after that record with id = 300, sorted by date under section A.
The output:
140, 26 Aug 2014 12:00, A
200, 30 Aug 2014 11:00, A
290, 02 Sep 2014 12:00, A
300, 26 Sep 2014 12:00, A <-- middle
302, 30 Oct 2014 11:23, A
590, 02 Oct 2014 12:00, A
600, 26 Nov 2014 00:00, A
I have a stupid approach:
get the date (let say it's 26 Sept 2014 12:00) of the specified id = 300 with section A
set a query to find records that the date is greater than and equal to 26 Sept 2014 12:00 ordered by date, limited by 3 records.
set a query to find records that the date is less than 26 Sept 2014 12:00 ordered by date, limited by 3 records.
combine two lists.
Is there any better approaches to just retrieve this kind of list in a query or in better performance? Thank you.
Let's your schema name be USER. You could use below mongo db query to fetch the result
$sort function :
1 represents ascending
-1 represents descending
Refer documentation : $Sort Documentation
Query will be :
db.user.aggregate({$match : { "id" : 300}},{$sort : {"date": 1 }},{$skip : 0},{$limit : 10});
$skip value will be your limit value after first query
db.user.aggregate({$match : { "id" : 300}},{$sort : {"date": 1 }},{$skip : 10},{$limit : 10});
Refer Documentation : Aggregation Documentation
$skip and $limit in aggregation framework
Here is a good example of using skip and limit which should help you achieve the SELECT TOP X or LIMIT X
Note: I'm assuming you want to use the aggregate framework based on the tagging of this question.
I believe this should do it
x = 300;
db.user.aggregate({$match : { "id" : {$lte: x+10,$gte: x-10 }},{$sort : {"date": 1 }}});

Updating/destroying EmbeddedDocuments in MongoMapper

I can't seem to figure out how to update or destroy EmbeddedDocuments in MongoMapper. Through Googling I've seen different methods like delete_if {} and others, but none seem to work for me semantically. Is there anything built-in to MongoMapper to help with this?
class Schedule
include MongoMapper::Document
key :name, String
key :description, String
key :active, Boolean, :default => false
many :periods
validates_presence_of :name
def activate!
set({:active => true}, :active => false)
self.active = true
end
end
class Period
include MongoMapper::EmbeddedDocument
key :number, Integer
key :text, String
key :start, Time
key :finish, Time
embedded_in :schedule
before_validation :number!
validates_presence_of :number
validates_presence_of :text
validates_presence_of :start
validates_presence_of :finish
validates_format_of :start, :with => /^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$/
validates_format_of :finish, :with => /^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$/
def number!
unless self.number
number = schedule.periods.count + 1
end
end
end
The follow test shows examples on how to update and remove embedded documents in two ways:
(1) via Ruby using standard Array accessors and methods, and
(2) via Mongo (MongoMapper / MongoDB) for update and removal of embedded documents on the DB server
References:
http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-delete_if
http://mongomapper.com/documentation/plugins/modifiers.html#set
http://www.mongodb.org/display/DOCS/Updating#Updating-%24set
Note that Hash keys containing '.' require use of the old ( => ) syntax. Hope that this helps.
test/unit/period_test.rb
require 'test_helper'
def ppp(obj)
puts obj.inspect.gsub(/(, |\[)#/, "\\1\n #")
end
class PeriodTest < ActiveSupport::TestCase
def setup
Schedule.delete_all
#today = Time.now.midnight
end
test "update and remove embedded documents" do
schedule = Schedule.create(name: 'George')
assert_equal(1, Schedule.count)
schedule.periods << Period.new(number: 1, text: 'period 1', start: #today + 8.hours, finish: #today + 9.hours)
schedule.periods << Period.new(number: 2, text: 'period 2', start: #today + 9.hours, finish: #today + 10.hours)
schedule.periods << Period.new(number: 3, text: 'period 3', start: #today + 10.hours, finish: #today + 11.hours)
schedule.periods.last.finish = #today + 12.hours #update in Ruby
schedule.save
assert_equal(1, Schedule.count)
puts "schedule with three periods --------"
ppp Schedule.first
schedule.periods.delete_if {|period| period.text == 'period 2'} #remove in Ruby
schedule.save
puts "schedule after removing period 2 in Ruby --------"
ppp Schedule.first
Schedule.set( {name: 'George', 'periods.text' => 'period 1'}, {'periods.$.finish' => #today + 10.hours} ) #update embedded document in MongoDB
puts "schedule after updatting period 1 via Mongo --------"
ppp Schedule.first
Schedule.pull( {name: 'George'}, { periods: { text: 'period 1'} } ) #remove embedded document in MongoDB
puts "schedule after pulling period 1 via Mongo --------"
ppp Schedule.first
end
end
output
Run options: --name=test_update_and_remove_embedded_documents
# Running tests:
schedule with three periods --------
#<Schedule _id: BSON::ObjectId('4ff732e77f11ba6fe9000001'), active: false, name: "George", periods: [
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000002'), finish: Fri, 06 Jul 2012 13:00:00 UTC +00:00, number: 1, start: Fri, 06 Jul 2012 12:00:00 UTC +00:00, text: "period 1">,
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000003'), finish: Fri, 06 Jul 2012 14:00:00 UTC +00:00, number: 2, start: Fri, 06 Jul 2012 13:00:00 UTC +00:00, text: "period 2">,
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000004'), finish: Fri, 06 Jul 2012 16:00:00 UTC +00:00, number: 3, start: Fri, 06 Jul 2012 14:00:00 UTC +00:00, text: "period 3">]>
schedule after removing period 2 in Ruby --------
#<Schedule _id: BSON::ObjectId('4ff732e77f11ba6fe9000001'), active: false, name: "George", periods: [
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000002'), finish: Fri, 06 Jul 2012 13:00:00 UTC +00:00, number: 1, start: Fri, 06 Jul 2012 12:00:00 UTC +00:00, text: "period 1">,
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000004'), finish: Fri, 06 Jul 2012 16:00:00 UTC +00:00, number: 3, start: Fri, 06 Jul 2012 14:00:00 UTC +00:00, text: "period 3">]>
schedule after updatting period 1 via Mongo --------
#<Schedule _id: BSON::ObjectId('4ff732e77f11ba6fe9000001'), active: false, name: "George", periods: [
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000002'), finish: Fri, 06 Jul 2012 14:00:00 UTC +00:00, number: 1, start: Fri, 06 Jul 2012 12:00:00 UTC +00:00, text: "period 1">,
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000004'), finish: Fri, 06 Jul 2012 16:00:00 UTC +00:00, number: 3, start: Fri, 06 Jul 2012 14:00:00 UTC +00:00, text: "period 3">]>
schedule after pulling period 1 via Mongo --------
#<Schedule _id: BSON::ObjectId('4ff732e77f11ba6fe9000001'), active: false, name: "George", periods: [
#<Period _id: BSON::ObjectId('4ff732e77f11ba6fe9000004'), finish: Fri, 06 Jul 2012 16:00:00 UTC +00:00, number: 3, start: Fri, 06 Jul 2012 14:00:00 UTC +00:00, text: "period 3">]>
.
Finished tests in 0.038952s, 25.6726 tests/s, 51.3452 assertions/s.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips