Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

242
Views
Bash loop para fusionar archivos en lotes para mongoimport

Tengo un directorio con 2,5 millones de archivos JSON pequeños. Son 104gb en disco. Son archivos de varias líneas.

Me gustaría crear un conjunto de matrices JSON a partir de los archivos para poder importarlos usando mongoimport en un tiempo razonable. Los archivos no pueden tener más de 16 mb, pero estaría feliz incluso si lograra obtenerlos en grupos de diez.

Hasta ahora, puedo usar esto para hacerlos uno a la vez a aproximadamente 1000/minuto:

 for i in *.json; do mongoimport --writeConcern 0 --db mydb --collection all --quiet --file $i; done

Creo que puedo usar "jq" para hacer esto, pero no tengo idea de cómo hacer que el bucle bash pase 10 archivos a la vez a jq. Tenga en cuenta que el uso de bash find da como resultado un error ya que hay demasiados archivos.

Con jq puede usar --slurp para crear matrices, y -c para hacer una sola línea json multilínea. Sin embargo, no puedo ver cómo combinar los dos en un solo comando.

Por favor ayuda con ambas partes del problema si es posible.

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Aquí hay un enfoque. Para ilustrar, he usado awk porque puede leer la lista de archivos en lotes pequeños y porque tiene la capacidad de ejecutar jq y mongoimport. Probablemente necesitará hacer algunos ajustes para hacer que todo sea más robusto, para probar errores, etc.

La idea es generar un script que pueda ser revisado y luego ejecutado, o usar el comando system() de awk para ejecutar los comandos directamente. Primero, generemos el script:

 ls *.json | awk -v group=10 -v tmpfile=json.tmp ' function out() { print "jq -s . " files " > " tmpfile; print "mongoimport --writeConcern 0 --db mydb --collection all --quiet --file " tmpfile; print "rm " tmpfile; files=""; } BEGIN {n=1; files=""; print "test -r " tmpfile " && rm " tmpfile; } n % group == 0 { out(); } { files = files " \""$0 "\""; n++; } END { if (files) {out();}} '

Una vez que haya verificado que esto funciona, puede ejecutar el script generado o cambiar las líneas "imprimir ..." para usar "sistema (....)"

Usando jq para generar el script

Aquí hay un enfoque solo jq para generar el script. Dado que la cantidad de archivos es muy grande, lo siguiente usa funciones que solo se introdujeron en jq 1.5, por lo que su uso de memoria es similar al script awk anterior:

 def read(n): # state: [answer, hold] foreach (inputs, null) as $i ([null, null]; if $i == null then .[0] = .[1] elif .[1]|length == n then [.[1],[$i]] else [null, .[1] + [$i]] end; .[0] | select(.) ); "test -r json.tmp && rm json.tmp", (read($group|tonumber) | map("\"\(.)\"") | join(" ") | ("jq -s . \(.) > json.tmp", mongo("json.tmp"), "rm json.tmp") )

Invocación:

 ls *.json | jq -nRr --arg group 10 -f generate.jq
over 4 years ago · Santiago Trujillo Report

0

Esto es lo que se me ocurrió. Parece funcionar y está importando a aproximadamente 80 por segundo en un disco duro externo.

 #!/bin/bash files=(*.json) for((I=0;I<${#files[*]};I+=500)); do jq -c '.' ${files[@]:I:500} | mongoimport --writeConcern 0 --numInsertionWorkers 16 --db mydb --collection all --quiet;echo $I; done

Sin embargo, algunos están fallando. He importado archivos de 105k, pero solo aparecieron 98547 en la colección de mongo. Creo que es porque algunos documentos son> 16mb.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!