0

I am trying to split my json object into multiple json arrays.

{
    "MusicCollection": [
        {
            "PutRequest": {
                "Item": {
                    "Artist": {"S": "No One You Know"},
                    "SongTitle": {"S": "Call Me Today"},
                    "AlbumTitle": {"S": "Somewhat Famous"}
                }
            }
        },
        {
            "PutRequest": {
                "Item": {
                    "Artist": {"S": "Acme Band"},
                    "SongTitle": {"S": "Happy Day"},
                    "AlbumTitle": {"S": "Songs About Life"}
                }
            }
        },
        {
            "PutRequest": {
                "Item": {
                    "Artist": {"S": "No One You Know"},
                    "SongTitle": {"S": "Scared of My Shadow"},
                    "AlbumTitle": {"S": "Blue Sky Blues"}
                }
            }
        }
    ]
}

Command in below post works in linux for splitting the file into multiple putRequest arrays.

jq -cM --argjson sublen '2' 'range(0; length; $sublen) as $i | .[$i:$i+$sublen]' \
input.json | split -l 1 -da 3 - meta2_

Reference: Split a JSON array into multiple files using command line tools

Directly running below command in command prompt gives me 3 put requests.

jq ".MusicCollection[]" music.json

However, when I used below for loop in batch script, it just gives me }.

    for /f "tokens=*" %%a in ('music.json') do (
        jq ".MusicCollection[]" music.json
        set array_value=%%a
    )

echo Array: %array_value%

Can someone please guide me as how I should get the same output of command prompt with the for loop?

Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
Dwarrior
  • 687
  • 2
  • 10
  • 26
  • It is not clear from your question what would you like to get as the result. Could you be so kind as to be more specific -- show the content of the resulting file (or each of them if you'd like to have the set of them) based on the input file you've shown in this question – jsxt Aug 16 '17 at 04:37
  • I'm not sure what exactly you're asking but... windows command prompt doesn't have an equivalent of an array type for variables. Is that what you're trying to get? – Jeff Mercado Aug 16 '17 at 05:23
  • @jsxt: I need an o/p in multiple files. Ex. If i define a batch size of 2 I should get 2 json objects as mentioned below in different files. File 1: { "MusicCollection": [{"PutRequest":{"Item":{"Artist":{"S":"No One You Know"},"SongTitle":{"S":"Call Me Today"},"AlbumTitle":{"S":"Somewhat Famous"}}}},{"PutRequest":{"Item":{"Artist":{"S":"Acme Band"},"SongTitle":{"S":"Happy Day"},"AlbumTitle":{"S":"Songs About Life"}}}}]} File 2: { "MusicCollection": [{"PutRequest":{"Item":{"Artist":{"S":"No One You Know"},"SongTitle":{"S":"Scared of My Shadow"},"AlbumTitle":{"S":"Blue Sky Blues"}}}}]} – Dwarrior Aug 16 '17 at 06:38
  • @JeffMercado: I am trying to write a batch script that can iterate through each array present inside the json object and generate multiple files. Output that I am trying to see is mentioned in above comment. Using jq split, I thought I could get the output redirected to text file, but somehow I am unable to achieve that. Thanks! – Dwarrior Aug 16 '17 at 06:45

2 Answers2

0

Since you have jq in your environment, it seems reasonable to assume that you could also use awk without too much difficulty. If so, you could pipe the JSONLines output of jq (invoked with the -c option) to an awk command along the following lines:

awk -v mx=2 'BEGIN{n=0}
     n%mx == 0 {
       nf++; close(out);
       out="OUTPUT."nf".json";
     }
     {n++; print > out}' 
peak
  • 105,803
  • 17
  • 152
  • 177
0

This one allows you to split putRequest to set of arrays having no more than 2 items

jq -c "[ .MusicCollection[] ] | range(0; length; 2) as $i | { MusicCollection: .[ $i:$i+2 ] }" input.json

I guess this could help you to understand the following script. It assumes that the names of each file generated match the pattern FileN (where N is a number).

@echo off

rem stop variable expansion while using them under loop
setlocal enabledelayedexpansion

rem initialize the counters
set /a "FILENUM=0"
set /a "ARRAYLENGTH=2"

for /f "tokens=*" %%a in ( '
    jq -c --argjson L "!ARRAYLENGTH!" "[ .MusicCollection[] ] | range(0; length; $L) as $i | { MusicCollection: .[ $i:$i+$L ] }" input.json
' ) do (
    rem set the counter to the next file
    set /a "FILENUM+=1"

    rem print results
    echo:File !FILENUM!:
    echo:%%~a
    echo:

    rem uncomment to turn on printing to files called FileN
    rem echo:%%~a>File!FILENUM!
)
jsxt
  • 1,097
  • 11
  • 28
  • Yes, it is possible but the method to avoid prionting EOL before EOF is a bit tricky. Look for the solution at ss64.com or dostips.com. – jsxt Aug 16 '17 at 14:08
  • Thanks so much! You have answered it in the simplest way. Not only I learnt how to use the jq expression, but also, how to use the batch file to achieve it in window. Just 2 questions though..I see a new line character at the end of each file. Is it possible to remove it? Further, the command prompt stops if I pass a huge file with ~2000 lines. Seems to be an issue with jq pipe? Even when I passed an absolute path - c:\cli\input.json, it didnt help. – Dwarrior Aug 16 '17 at 15:05
  • Thanks for answering the 1st part. Actually, I updated it with 2nd question. I have accepted your answer, but let me know if I need to create another post for the jq crashing. I referred below link but didn't help. https://stackoverflow.com/questions/45613545/jq-crashing-under-windows-10-using-any-command – Dwarrior Aug 16 '17 at 15:09
  • If my file has 78 records, does this expression makes sense? My understanding is 9 files will be created with each having 9 objects. Correct me if I am wrong, because I see that its generating only 1 file now. jq -c "[ .MusicCollection[] ] | range(0; length; 9) as $i | { MusicCollection: .[ $i:$i+9 ] }" input.json – Dwarrior Aug 16 '17 at 16:26
  • Good practice is to ask another question in new thread. So do it if you didn't find any relevant answer for your issue. The script I have provided will work with any reasonable numeric value for subarray length (2 or 9 etc). I have updated the script in my answer above to make it a little bit more flexible and convenient for the future. – jsxt Aug 16 '17 at 20:18