http://qs321.pair.com?node_id=1208707

Bobert1234 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm trying to iterate through a json decoded string (using JSON::PP's decode) in order to replace individual elements with corresponding perl objects (e.g. strings starting with ISODate with Time::Moment). i keep running into issues due to the structure of the json_decoded object. i'm new to per and traversing the structure to get to the parts i want to replace is a nightmare of hash/array referencing/dereferencing. here's what i have. could someone please point me to where i'm going wrong?
my $qstr = 'MONGOQUERY[ { $match: { $or : [{"prefix" : "27450500"}, {"creationDate": ISODa +te("2017-06-18T12:52:16.000")}] } }, { $project: { _id:0, prefix:1 } }, ]'; $qstr=~s/MONGOQUERY//gs; $qstr=~s/ISODate\("([^)]*?)\)/"ISODate$1/gs; #Timestamp,ISODate, NumberDecimal,NumberLong,NumberInt,Symbol my $qarrayref = JSON::PP->new->allow_nonref->relaxed->allow_barekey->l +oose->decode($qstr); my $rlimit=50; repl_mongo(\@{$qarrayref},$rlimit); sub repl_mongo{ if($_[1]>0){ open(my $fh, '>>', '/tmp/mongosample.txt'); if(ref($_[0]) eq 'ARRAY'){ foreach my $item(@{$_[0]}){ repl_mongo($item,$_[1]-1 ); } }elsif(ref($_[0]) eq 'HASH'){ foreach my $item (keys %{$_[0]}){ repl_mongo($key,$_[1]-1 ); } }else{ if(index("ISODate", $_[0]) >= 0){ $_[0] =~s/ISODate//gs; # $_[0] =Time::Moment->from_string($_[0]); } } close $fh; } } open(my $fh, '>>', '/tmp/mongosample.txt'); print $fh Dumper($qarrayref); close $fh;

Replies are listed 'Best First'.
Re: iterating through json decode
by poj (Abbot) on Feb 08, 2018 at 14:33 UTC
    where i'm going wrong?

    Add use strict; use warnings;

    #foreach my $item (keys %{$_[0]}){ # repl_mongo($key,$_[1]-1 ); foreach my $key (keys %{$_[0]}){ repl_mongo($_[0]->{$key},$_[1]-1 ); }

    Also see index

    #if (index("ISODate",$_[0]) >= 0){ if (index($_[0],"ISODate") >= 0){

    Note to use Time::Moment->from_string($string); The string must consist of a complete date representation and time of day followed by a zone designator.

    poj
      Thank you very much poj ! that was super helpful.
Re: iterating through json decode
by Eily (Monsignor) on Feb 08, 2018 at 14:38 UTC

    \@{$ref} is the same as $ref, because @{$ref} accesses the array that $ref points to, and adding a \ gets the same reference.

    While accessing @_ inside a function does work, I think you should put your arguments in variable (which should be done when @_ isn't a list of similar things but each argument has its own meaning. So:

    sub repl_mongo{ my ($ref, $depth) = @_; return unless $depth; if (ref($ref) eq 'ARRAY') { ... }
    (and basically replace every use of $_[0] by $ref, and $_[1] by $depth).

    foreach my $item (keys %{$_[0]}){ repl_mongo($key,$_[1]-1 ); } The loop variable is $item, but you access $key. Do you have strict on? It should have told you about that.

    And for the date conversion, after you have found that a string starts with ISODate (that's index exactly 0 by the way) you can use substr to extract the date part (which will always be at the same positions, starting from the 8th character).

Re: iterating through json decode
by QM (Parson) on Feb 08, 2018 at 13:54 UTC
    Can you not:
    use JSON;

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

Re: iterating through json decode
by hippo (Bishop) on Feb 08, 2018 at 14:24 UTC

    Your repl_mongo looks to be a reinvention of Data::Leaf::Walker->each(). It might be simpler just to use that instead?