Creación de Scripts#

La creación de scripts es el último paso para el desarrollo de reportes. Un script es el encargado de generar las consultas necesarias a la base de datos y procesar la información aplicando operaciones específicas para mostrar la data solicitada.

Prudencia

El desarrollo de un script es un proceso delicado y dependerá de qué y cómo se mostrará la información. Por favor, el siguiente contenido explica el proceso para desarrollar un script, pero está basado en un reporte específico con requerimientos particulares. Tenga en cuenta que todos los reportes son únicos y pueden cambiar.

Una vez que haya desarrollado y esté seguro de su script, cárguelo en la aplicación web.

Ver también

Consulte Cargar script para más información.

Estructura de archivos#

Dentro del Repositorio infosync_scripts encontrarán los archivos correspondientes al back-end del reporte. Por favor, sigan los siguientes pasos para crear los archivos necesarios y continúen revisando cada sección correspondiente a la explicación sobre su contenido.

  1. Cree una carpeta exclusiva dentro de la carpeta infosync-scripts para sus reportes en caso de no contar con una.

Nota

Identifique a la carpeta con el nombre de su empresa o el cliente que lo requiera.

  1. Si está creando un reporte y carpeta desde cero, cree los dos archivos correspondientes, las cuales incluyen:

  • account_settings.py: Configuraciones de la cuenta del cliente (uno por cuenta).

  • reporte_nombre_script.py: Consultas a la base de datos.

Importante

En las siguientes secciones se explicará el contenido de cada archivo. Sin embargo, considere que NO se tiene un estándar establecido para el contenido. No obstante, utilice los ejemplos como base para sus proyectos futuros.

Archivo account settings#

Prudencia

El archivo account_settings escrito en python contiene información y configuraciones sensibles de la cuenta del cliente.

Si requiere hacer actualizaciones en el archivo account_settings y no encuentra el archivo, lo podrá encontrar con el nombre del cliente seguido de settings, por ejemplo: linkaform_settings.

El contenido de un archivo account_settings varía dependiendo de lo que el cliente requiera. Sin embargo, lo que un reporte necesita de este archivo es el entorno de ejecución y lo que contiene el diccionario config.

Identifique las líneas de código 4-5 y 8-9. Si desea apuntar y hacer la petición del script a producción, debe habilitar las líneas de código correspondientes a la misma. En caso contrario, si desea apuntar al script almacenado en preproducción, descomente las líneas de código de preproducción.

Ahora, localice la variable MONGODB_PASSWORD ubicada en línea de código 28, hace referencia a la contraseña de mongo.

Nota

Solicite a soporte técnico apoyo para obtener la contraseña correspondiente a mongo.

Identifique las líneas de código 33-34, debe colocar el USER_ID y ACCOUNT_ID de la cuenta padre.

Ver también

Consulte el siguiente enlace para Ver información de la cuenta .

Ubique la variable AUTHORIZATION_EMAIL_VALUE (línea 42) y ajuste de acuerdo al correo de la cuenta padre.

En la variable API_KEY (línea 43) copie y pegue la la clave alfanumérica generada.

Ver también

Consulte: a Generar API key para más información.

Revise la linea 46, settings.config.update(config) se utiliza para aplicar las configuraciones definidas en el diccionario config al módulo settings. Esto es útil porque permite modificar dinámicamente las configuraciones de la aplicación sin tener que cambiar el código fuente directamente.

 1from linkaform_api import settings # Configuraciones de la api
 2
 3# --------- ENTORNO PRODUCCIÓN ---------
 4settings.mongo_hosts = 'db2.linkaform.com:27017,db3.linkaform.com:27017,db4.linkaform.com:27017'
 5settings.mongo_port = 27017
 6
 7# --------- ENTORNO PREPRODUCCIÓN ---------
 8# settings.mongo_hosts = 'dbs2.lkf.cloud:27918'
 9# settings.mongo_port = 27918
10
11config = {
12    # Correo de la cuenta padre
13    'USERNAME' : 'correo.cuenta.padre@gmail.com',
14    'PASS' : '',
15
16    # Colección de MongoDB para almacenar las respuestas de los formularios
17    'COLLECTION' : 'form_answer',
18
19    # No cambiar
20    'HOST' : 'app.linkaform.com',
21    'PROTOCOL' : 'https', #http o https
22
23    # Variables definidas para el entorno de ejecución
24    'MONGODB_PORT': settings.mongo_port,
25    'MONGODB_HOST': settings.mongo_hosts,
26
27    'MONGODB_USER': 'account_id',
28    'MONGODB_PASSWORD': 'pass',
29
30    'PORT' : settings.mongo_port,
31
32    # Id de la cuenta padre
33    'USER_ID' : 123,
34    'ACCOUNT_ID' : 123,
35
36    'KEYS_POSITION' : {},
37    'IS_USING_APIKEY' : False,
38    'USE_JWT' : True,
39    'JWT_KEY':'',
40
41    # Configuración de api key
42    'AUTHORIZATION_EMAIL_VALUE' : 'correo.cuenta.padre@gmail.com'',
43    'API_KEY':"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
44}
45
46settings.config.update(config)

Atención

Cualquier cambio dentro de este archivo debe ser ejecutado solamente en su entorno local por ningún motivo son cambios que deben actualizarse en el repositorio.

Archivo py#

El archivo py en el repositorio infosync_scripts contiene las consultas y funciones necesarias para procesar y extraer la información almacenada en la base de datos.

En la siguiente pestaña desplegable, observe el bloque de código, el cual representa de manera general las variables y funciones principales que componen a un archivo py.

En contenido posterior podrá encontrar detalles sobre las funciones más relevantes, resaltando los elementos que puede personalizar.

Vista general
 1#-*- coding: utf-8 -*-
 2import simplejson, sys
 3from linkaform_api import settings, network, utils
 4from bson import ObjectId
 5import time, pytz, math
 6from datetime import datetime, timedelta, date
 7from account_settings import *
 8from unicodedata import normalize
 9
10class ReportModel(): ...
11
12def get_date_query(date_from, date_to): ...
13
14#---FORMAT
15def get_format_firstElement(data): ...
16
17#-- FUNCTION QUERYS
18def query_report_first(date_from, date_to, buscador, variedad): ...
19
20if __name__ == "__main__":
21    print(sys.argv)
22    all_data = simplejson.loads(sys.argv[2])
23    #--Filtros
24    data = all_data.get("data", {})
25    date_to = data.get("date_to",'')
26    date_from = data.get("date_from",'')
27    buscador = data.get("buscador",'')
28    variedad = data.get("variedad",'')
29    #--Report Model
30    report_model = ReportModel()
31
32    if date_to or date_from :
33        #--CREDENCIAL
34        settings.config.update(config)
35        lkf_api = utils.Cache(settings)
36        net = network.Network(settings)
37        #--TOKEN
38        #jwt_complete = simplejson.loads(sys.argv[2])
39        #config["USER_JWT_KEY"] = jwt_complete
40        #--KEY
41        jwt_key = lkf_api.get_jwt(api_key=settings.config['API_KEY'])
42        config["USER_JWT_KEY"] = jwt_key
43        cr = net.get_collections()
44        #--EJECUCIONES
45        query_report_first(date_from, date_to, buscador, variedad)
46        sys.stdout.write(simplejson.dumps(report_model.print()))
47    else:
48        sys.stdout.write(simplejson.dumps({"json": {}}))

Main#

Un Script comienza a ejecutarse a partir del ultimo bloque de código main. Por favor, lea los comentarios dentro del código y considere las siguientes anotaciones.

Observe la línea de código 3, print(sys.argv), que se encarga principalmente de generar un log para depurar y obtener detalles sobre los argumentos del script.

Prudencia

Por ningún motivo comente o elimine esta línea de código. Consulte Log de script y revise la interpretación de la misma.

Identifique el bloque de código de la 7 a la 11, que procesa un objeto JSON presente en el tercer elemento de la lista sys.argv. Revise Interpretación log de script .

Ver también

El método get se utiliza para obtener el valor asociado con una clave en un diccionario.

  • Si la clave existe en el diccionario, get devuelve el valor asociado con esa clave.

  • Si la clave no existe en el diccionario, get devuelve None por defecto.

  • Si se proporciona un valor por defecto como segundo argumento, ese valor se devuelve si la clave no está presente en el diccionario.

Ahora, considere que el código presente es un ejemplo básico y puede cambiar según sus necesidades. Por ejemplo, para procesar las ejecuciones, considere aplicar alguna condicional en caso de no recibir un valor, con en el caso actual.

El siguiente código contiene una condicional y solamente ejecutará su contenido si recibe una fecha desde (date_to) o una fecha hasta (date_from) en la línea 14. En caso de que el filtro no contenga ningún valor, lo que va a mostrar será una cadena vacía (línea 30).

Concéntrese en el bloque 19-23, aquí, se están actualizando las configuraciones en el módulo settings con los valores del diccionario config. Después de la actualización de la configuración, se utilizan las clases utils.Cache y network.Network para interactuar con la API de Linkaform.

Ver también

Consulte el archivo account settings para más detalles.

Si la autenticación se desea realizar a partir del token (26-27), se obtiene el token (jwt_complete) y luego lo asigna a la propiedad USER_JWT_KEY en el diccionario de configuración .

De otra manera, si la autenticación se realiza a partir de la API key (30-31), se llama al método get_jwt de la API de Linkaform, proporcionándole la API key almacenada en la configuración (settings.config['API_KEY']).

El método get_jwt genera un token a partir de la API key y devuelve ese token, que luego se asigna a la propiedad USER_JWT_KEY en el diccionario de configuración .

Prudencia

Si requiere hacer la autenticación por el usuario que abre o ejecuta el reporte, deberá comentar el bloque correspondiente a la API key y habilitar el Token para recibirla en la petición.

En la línea 38, encontrará las ejecuciones, que básicamente son las funciones encargadas de gestionar las consulta a la base de datos. En este caso, se trata de un reporte con una sola función de consulta (query_report_first).

Nota

Las funciones de consulta no devuelven los datos como tal, sino que son almacenadas en el diccionario report_model de la función get_format_firstElement.

Identifique la instrucción en la línea 39, se encarga de escribir la representación en formato JSON del diccionario que devuelve la función print de la clase ReportModel en la salida. Es decir, recibe un json con la data de la request que se hace.

Nota

Por favor, continúe revisando el flujo de la documentación para comprender las funciones.

 1if __name__ == "__main__":
 2    # Log del script
 3    print(sys.argv)
 4    all_data = simplejson.loads(sys.argv[2])
 5
 6    #--Filtros
 7    data = all_data.get("data", {})
 8    date_to = data.get("date_to",'')
 9    date_from = data.get("date_from",'')
10    buscador = data.get("buscador",'')
11    variedad = data.get("variedad",'')
12
13    #--Report Model
14    report_model = ReportModel()
15
16    if date_to or date_from :
17        #--CREDENCIAL
18        # Actualiza la configuración con los valores definidos en el diccionario "config"
19        settings.config.update(config)
20
21        # Crea instancias de las clases utils.Cache y network.Network con la configuración actualizada
22        lkf_api = utils.Cache(settings)
23        net = network.Network(settings)
24
25        # Autenticación con Token JWT
26        #jwt_complete = simplejson.loads(sys.argv[2])
27        #config["USER_JWT_KEY"] = jwt_complete
28
29        # Autenticación con API Key
30        jwt_key = lkf_api.get_jwt(api_key=settings.config['API_KEY'])
31        config["USER_JWT_KEY"] = jwt_key
32
33        # Habilita el acceso a las colecciones de la consulta.
34        cr = net.get_collections()
35
36        #--EJECUCIONES
37        # Llama a la función y envía parámetros
38        query_report_first(date_from, date_to, buscador, variedad)
39        sys.stdout.write(simplejson.dumps(report_model.print()))
40    else:
41        sys.stdout.write(simplejson.dumps({"json": {}}))

Funciones#

Para definir las funciones encargadas de gestionar las peticiones a la base de datos, deben definirse siguiendo el estándar snake_case de Python.

1def nombre_funcion(parámetro1, parámetro2, parámetro3)

Para estructurar una query, dependerá de los requerimientos que necesite. Sin embargo, tenga en cuenta los siguientes puntos que la mayoría de los reportes comparten:

  • Cuando realiza un query para consultar datos reales de una forma, necesita forzosamente el identificador de la forma.

Ver también

Consulte Ver ID de la forma para más información.

  • Se requiere el ID del campo para especificar que se necesita la data del mismo.

Ver también

Consulte la sección Opciones en la documentación para el usuario y consulte específicamente Opciones avanzadas .

A continuación se detallan algunos ejemplos en base a los casos anteriores.

La siguiente función se utiliza para consultar datos de un formulario. Utilice este ejemplo como base para preparar su propia consulta personalizada, pero tenga mucho cuidado y preste atención a las notas para realizar modificaciones según lo requiera.

Por favor, revise y lea los comentarios del código de la función al final de esta pestaña sincronizada y regrese aquí para seguir el flujo de la función.

Se define la función query_report_first que recibe cuatro parámetros correspondientes a los filtros del punto de entrada principal del script (main) .

1def query_report_first(date_from, date_to, buscador, variedad):

La variable global report_model modifica su valor en base a esta función para presentar la estructura de los diccionarios.

1global report_model

Ver también

consulte la Clase ReportModel para más detalles.

En el siguiente bloque de código, se crea un diccionario denominado match_query que representa las condiciones iniciales de la consulta. Este diccionario actúa como filtros obligatorios que especifican las condiciones de dónde y cómo extraer los datos.

  • Asegúrese de modificar el valor de la clave form_id de acuerdo al identificador del formulario al que desea extraer la información.

Ver también

Revise Ver ID de la forma para más información.

  • La clave y valor "deleted_at":{"$exists":False}, propio de MongoDB, indica que no se desea consultar información previamente eliminada.

1match_query = {
2        "form_id": 98116,
3        "deleted_at":{"$exists":False},
4    }

Por lo general, el diccionario match_query contiene las claves form_id y deleted_at. Sin embargo, considere y agregue otros filtros a su consulta según lo requiera. En el siguiente bloque de código, se presentan dos nuevos filtros; por favor, lea detenidamente los comentarios para comprender su función.

Prudencia

Asegúrese de que los nuevos filtros sean constantes, es decir que su valor no cambie.

 1match_query = {
 2    "form_id": 75791,
 3    "deleted_at":{"$exists":False},
 4
 5    # Busca documentos en la colección donde el metadato "created_by_name" no contenga ninguno de los siguientes valores
 6    "created_by_name":{"$nin":['Luis Marquez', 'Andrea Lopez', 'Jose Chavez', 'Esteban Martinez']},
 7
 8    # Busca todos los documentos que el campo contenga el valor de "montaje_terminado".
 9    "answers.11ci37d99a03dd17b1f6ff": "montaje_terminado",
10}

Nota

La palabra reservada answers seguido de la cadena alfanumérica (ID) se utiliza para indicar que se está accediendo a un campo especifico del formulario.

Consulte la sección Opciones en la documentación para el usuario y consulte específicamente Opciones avanzadas para habilitar la visualización de los IDs de los campos. Copie y pegue según sea necesario.

Los siguientes filtros son opcionales, es decir, solo se aplican si están presentes ambas, uno o ninguno en la solicitud; de lo contrario, no afectan la condición de la consulta y se descartan.

1# Actualiza la consulta para incluir el filtro de 'buscador' y 'variedad' si está presente y no contiene '--'
2if buscador and '--' not in  buscador:
3    match_query.update({"answers.": buscador})
4
5if variedad and '--' not in variedad:
6    match_query.update({"answers.":variedad })
7
8#match_query.update(get_date_query(date_from, date_to))

Considere el siguiente ejemplo, observe las condicionales que actualizan la consulta (match_query) según los valores de los filtros date_from y date_to.

 1# Si "date_from" tiene algún valor y si no contiene la cadena '--', se actualiza la consulta (match_query) con una condición de rango utilizando $gte (mayor o igual) para el campo específico.
 2if date_from and '--' not in  date_from:
 3    match_query.update({"answers.643d9b19b6b0dd38ef4cbdbc": {'$gte': date_from}})
 4
 5# Si "date_to" tiene algún valor y si no contiene la cadena '--', se actualiza la consulta (match_query) con una condición de rango utilizando $lte (menor o igual) para el campo específico.
 6if date_to and '--' not in  date_to:
 7    match_query.update({"answers.643d9b19b6b0dd38ef4cbdbc": {'$lte': date_to}})
 8
 9# Si tanto "date_from" como "date_to" tienen valores y si ninguno de ellos contiene la cadena '--', se actualiza la consulta con una condición de rango utilizando $gte y $lte para abarcar un rango de fechas.
10if date_from and '--' not in  date_from and date_to and '--' not in  date_to:
11    match_query.update({"answers.643d9b19b6b0dd38ef4cbdbc": {'$gte':date_from,'$lte':date_to}})

Nota

Se menciona que son filtros opcionales porque comúnmente se reciben fechas. Por ejemplo, si recibe date_from (fecha desde), la consulta comprende realizar búsquedas desde la fecha seleccionada hasta el día de la consulta. (Considere los otros casos).

Ver también

Consulte la documentación oficial de los operadores relacionales de MongoDB o acceda al siguiente enlace que proporciona ejemplos para preparar sus propios filtros.

Con frecuencia, en la mayoría de los reportes, encontrará la función get_date_query . Esta función actualiza la consulta mediante condiciones de fecha. La razón detrás de esta práctica es que, como se mencionó anteriormente, la mayoría de los reportes incorporan tanto date_from como date_to como filtros.

1match_query.update(get_date_query(date_from, date_to))

Ver también

Consulte la función get_date_query para más detalles.

El siguiente código es la estructura de una consulta muy sencilla. En términos generales, se están utilizando operadores de agregación para filtrar documentos que cumplen con otros criterios. Por favor, revise los comentarios dentro del código.

  • Observe la línea de código 7. Es un documento apuntando a un metadato. Los metadatos permiten mostrar información descriptiva del registro, los mas utilizados son los siguientes:

Metadatos

Descripción

created_at

Fecha de creación de registro en formato “YYYY-MM-DD HH:mm:ss”.

created_by_name

Nombre del usuario que creó el registro.

folio

Folio del registro.

version

Versión del registro.

  • Observe las líneas de código 9-13. La consulta (query) selecciona a los campos para extraer la data de los formularios utilizando el ID del campo.

Nota

Recuerde que la palabra reservada answers seguido de la cadena alfanumérica (ID) se utiliza para indicar que se está accediendo a un campo especifico del formulario.

Si necesita acceder a un campo dentro de un Campo catálogo o Campo grupo repetitivo , primero coloque el ID del catálogo o grupo repetitivo seguido del ID del campo. Por ejemplo:

1"tienda":"$answers.63dc0f1ec29b8336b7b72613.63dc0f1ec29b8336b7b72616",

Consulte la sección Opciones en la documentación para el usuario y consulte Opciones avanzadas para habilitar la visualización de los IDs de los campos. Copie y pegue según sea necesario.

 1query = [
 2    # Filtra el documento de acuerdo a los filtros aplicados en "match_query" (id de la forma y la especificación de que no se desea consultar información previamente eliminada.)
 3    {"$match": match_query},
 4    # Selecciona a los campos específicos para extraer la información de los campos del formulario a traves de su ID.
 5    {"$project": {
 6        "_id":1,
 7        # Metadato folio
 8        "folio":"$folio",
 9        # Campos
10        "nombre_usuario":"$answers.64d66dc5d738a20c816b5",
11        "paterno_usuario":"$answers.64d66dc5d738a20c816b6",
12        "materno_usuario":"$answers.64d66dc5d738a20c82416b7",
13        "cantidad":"$answers.64d66dc5d7a20c82416ba",
14        "fecha":"$answers.64d66dc5d738a20c82416bc",
15    }},
16    # Ordena los documentos resultantes en orden ascendente según el metadato "created_at"
17    {"$sort": {"created_at":1}}
18]

Prudencia

La query dependerá de los datos que necesite extraer de sus formularios o si desea aplicar algún tipo de agrupamiento u operación que le permita mongodb.

Si desconoce de algunos elementos de mongodb, consulte la sección query para obtener una breve descripción

Las siguientes instrucciones son importantes y varían según lo requiera.

1result = cr.aggregate(query)
2get_format_firstElement(result)

En este caso, result = cr.aggregate(query) ejecuta la consulta de agregación y obtiene un cursor (result) que apunta a los resultados generados por el pipeline de agregación .

Con el método aggregate se accede a los pipelines de agregación de la consulta (query). En lugar de iterar sobre el cursor para procesar cada documento , se pasa directamente el cursor como parámetro a la función get_format_firstElement para aplicar un nuevo formateo.

En el siguiente caso, se crea una lista vacía llamada data para almacenar los resultados obtenidos de la iteración del cursor. La expresión cr.aggregate(query) ejecuta una consulta de agregación y devuelve un cursor que apunta a los resultados de esa consulta. Luego, utilizando una comprensión de lista [x for x in result], se itera sobre el cursor para extraer todos los documentos y se almacenan en la lista data. En última instancia, data contiene una lista con la información consultada de la base de datos.

1data = []
2result = cr.aggregate(query)
3data = [x for x in result]
4return data;

Ver también

Si tiene alguna duda respecto algún termino usado en las consultas, revise la sección query para más información.

Para visualizar el código completo de la función query_report_first, por favor, haga clic en el siguiente menú desplegable.

Función query_report_first
 1def query_report_first(date_from, date_to, buscador, variedad):
 2    global report_model
 3
 4    # Construcción de la consulta inicial para MongoDB
 5    match_query = {
 6        "form_id": 98116,
 7        "deleted_at":{"$exists":False},
 8    }
 9
10    # Actualiza la consulta para incluir el filtro de 'buscador' y 'variedad' si está presente y no contiene '--'
11    if buscador and '--' not in  buscador:
12        match_query.update({"answers.": buscador})
13
14    if variedad and '--' not in variedad:
15        match_query.update({"answers.":variedad })
16
17    #match_query.update(get_date_query(date_from, date_to))
18
19    # Definición de la consulta de agregación para MongoDB
20    query = [
21        # Filtra el documento de acuerdo a los filtros aplicados en "match_query" (id de la forma y la especificación de que no se desea consultar información previamente eliminada.)
22        {"$match": match_query},
23        # Selecciona a los campos específicos para extraer la información de los campos del formulario a traves de su ID.
24        {"$project": {
25            "_id":1,
26            "folio":"$folio",
27            "nombre_usuario":"$answers.64d66dc5d738a20c816b5",
28            "paterno_usuario":"$answers.64d66dc5d738a20c816b6",
29            "materno_usuario":"$answers.64d66dc5d738a20c82416b7",
30            "cantidad":"$answers.64d66dc5d7a20c82416ba",
31            "fecha":"$answers.64d66dc5d738a20c82416bc",
32        }},
33        # Ordena los documentos resultantes en orden ascendente según el metadato "created_at"
34        {"$sort": {"created_at":1}}
35    ]
36    # Ejecución de la consulta en la colección usando el método aggregate
37    result = cr.aggregate(query)
38    # Llamada a la función para procesar el resultado de la consulta
39    get_format_firstElement(result)
Funciones personalizadas#

Las funciones personalizadas se crean para hacer cálculos específicos con la data. En otras palabras, independientemente de cómo se obtenga la información a través de los filtros especificados, es posible manipular la información y presentarla de una manera diferente.

Por ejemplo, suponga que tiene una lista con información en un campo que representa las horas trabajadas y desea multiplicar ese valor por el salario por hora, buscando presentar una tabla con los salarios totales. Para lograr esto, se requiere una función personalizada que permita realizar esa operación y obtener una nueva lista con los datos tratados.

Importante

Este apartado tiene como objetivo explicar ejemplos sobre funciones personalizadas, pero no pretende ser un tutorial detallado sobre cómo crearlas. Recuerde que la creación de dichas funciones dependerá de lo que desee presentar y requerirá utilizar su experiencia en programación para desarrollarlas.

La función get_format_firstElement() se encarga de procesar y dar formato a los resultados obtenidos de la consulta.

Esta función toma el cursor de documentos, extrae información específica de cada documento y la estructura agregándola a la lista dentro de la clave firstElement del modelo de reporte (report_model).

Nota

Si ejecuta report_model.print(), obtendrá un diccionario que muestra la estructura de self.json, y podrá visualizar cómo la información se organiza dentro de firstElement.

Consulte la Clase ReportModel para más detalles.

 1def get_format_firstElement(data):
 2    # Indica que la función utilizará la variable global report_model.
 3    global report_model
 4
 5    # Itera sobre cada documento en el cursor data
 6    for x in data:
 7        # Imprime el documento actual (utilizada en la depuración).
 8        print(x);
 9        print('==============');
10
11        # Extrae valores específicos del documento utilizando el método get (si no existen, se asigna un valor predeterminado)
12
13        # Extrae el valor del campo "_id" del documento. Si el campo no existe, asigna una cadena vacía ''. Convierte el valor a cadena.
14        record_id = str(x.get('_id',''))
15        folio = x.get('folio','')
16        nombre_usuario = x.get('nombre_usuario','')
17        paterno_usuario = x.get('paterno_usuario','')
18        materno_usuario = x.get('materno_usuario','')
19        cantidad = x.get('cantidad')
20        fecha = x.get('fecha','')
21
22        # Agrega un diccionario con los valores extraídos al modelo de reporte
23        report_model.json['firstElement']['data'].append({
24            'record_id':record_id,
25            'folio':folio,
26            'nombre_usuario':nombre_usuario,
27            'paterno_usuario':paterno_usuario,
28            'materno_usuario':materno_usuario,
29            'cantidad':cantidad,
30            'fecha':fecha,
31        })
Query#

Prudencia

El siguiente contenido ofrece una visión rápida de los elementos básicos de una consulta en MongoDB útiles en los reportes, pero no constituye un tutorial completo. Por favor, consulte la documentación oficial de MongoDB o visite MongoDB University si aún no está familiarizado.

Una query es una solicitud estructurada para recuperar información específica de la base de datos de MongoDB . Una query puede ser tan simple o muy estructurada, según lo requiera.

Un documento es la representación en formato BSON de la información almacenada en la base de datos. Puede contener datos jerárquicamente estructurados, similar a un objeto JSON, con una estructura de pares clave-valor. Las claves son cadenas y los valores pueden ser de varios tipos.

Una colección es un conjunto lógico de documentos, comparable a una tabla en una base de datos relacional. A diferencia de una tabla, no impone un esquema fijo; cada documento puede tener campos diferentes sin necesidad de definir la estructura previamente.

En este ejemplo, cada clave (como nombre, edad, correo) representa un campo en el documento y los valores asociados son los datos almacenados. Además, el documento puede contener campos anidados (dirección) y un array (intereses).

Importante

La clave _id es el identificador único para el documento. Si no se proporciona un ID al documento, MongoDB asignará automáticamente un ObjectId.

 1{
 2"_id": ObjectId("5f7a1efb89f6a74f8c3cf45a"),
 3"nombre": "Juan Pérez",
 4"edad": 30,
 5"correo": "juan.perez@example.com",
 6"direccion": {
 7    "calle": "123 Main Street",
 8    "ciudad": "Ciudad Ejemplo",
 9    "codigo_postal": "12345"
10},
11"intereses": ["lectura", "viajes", "tecnología"]
12}

En MongoDB, existe un concepto llamado agregación, donde se utilizan operadores que procesan documentos y devuelven resultados calculados. Cada etapa realiza una operación específica en los datos durante la agregación. Algunas de las etapas más usadas en los reportes son:

Comando

Descripción

$match

Filtra documentos que cumplen con ciertos criterios.

$group

Agrupa documentos según un campo específico y realiza operaciones de agregación en esos grupos.

$sort

Ordena los documentos según un campo especificado. Utilice 1 (orden ascendente) y -1 (orden descendiente).

$limit

Limita el número de documentos que pasan a la siguiente etapa.

$project

Proyecta (selecciona) campos específicos para el resultado final.

$count

Cuenta el número de documentos que pasan a través de la etapa.

$set

Asigna un valor a un nuevo campo o modifica un campo existente.

$out

Escribe el resultado de la agregación en una nueva colección.

Un pipeline de agregación es una parte específica del proceso de agregación. Es una serie secuencial de etapas (operadores) que se aplican a los documentos en una colección.

Aquí hay un ejemplo de un pipeline de agregación utilizando algunas de las etapas mencionadas. Este pipeline realiza una serie de operaciones en una colección para filtrar, agrupar, ordenar, limitar y proyectar datos según las necesidades específicas.

1[
2    { $match: { field1: value1 } },
3    { $group: { _id: "$field2", total: { $sum: "$field3" } } },
4    { $sort: { total: -1 } },
5    { $limit: 10 },
6    { $project: { _id: 0, groupName: "$_id", totalAmount: "$total" } }
7]

Ver también

Para más información consulte conjunto de agregación .

Un método generalmente se refiere a una función o procedimiento que se puede invocar para realizar una operación específica en la base de datos. Considere los siguientes métodos:

Método

Descripción

db.collection.aggregate()

Proporciona acceso al canal de agregación.

db.collection.count()

Se ajusta count para devolver un recuento del número de documentos en una colección o vista.

db.collection.dataSize()

Devuelve el tamaño de la colección. Envuelve el size campo en la salida de collStats.

db.collection.drop()

Elimina la colección especificada de la base de datos.

db.collection.find()

Realiza una consulta sobre una colección o una vista y devuelve un objeto de cursor.

Ver también

Revise todos los métodos que MongoDB ofrece.

Un cursor es un puntero que permite recorrer los resultados de una query (consulta) uno a uno. Es especialmente útil al trabajar con conjuntos de datos extensos, ya que no es necesario cargar todo en la memoria simultáneamente. Sin embargo, es importante tener en cuenta que si se cierra el cursor, ya no se podrá acceder a los datos a través de él.

Ver también

Consulte el siguiente enlace para ejemplos y más detalles sobre un cursor .

Clase ReportModel#

La clase ReportModel() es opcional, pero es utilizada para representar una estructura de los diccionarios de datos para formatear y enviar respuestas a alguna petición.

El diccionario self.json tiene la clave firstElement que apunta a la estructura de un elemento específico para organizar la data, en este caso se trata de una tabla definida en la estructura html.

Ver también

Consulte la sección Content del reporte si necesita más detalles.

La función print() construye y devuelve un nuevo diccionario con la misma estructura que self.json, pero sin hacer referencia directa a la instancia de la misma clase. Por favor, lea los comentarios dentro del código.

Importante

En este caso, la función print() en la clase no tiene relación con la funcionalidad incorporada de Python print para imprimir en la consola.

 1class ReportModel():
 2    def __init__(self):
 3        # Estructura de datos predefinida
 4        self.json = {
 5            "firstElement":{
 6                "data": [],
 7            }
 8
 9    def print(self):
10        # Crea un nuevo diccionario 'res' con una clave 'json' que apunta a un diccionario vacío (utilizado para almacenar la estructura y datos formateados)
11        res = {'json':{}}
12        # Itera sobre las claves del diccionario self.json para copiar la estructura y datos al nuevo diccionario
13        for x in self.json:
14            # Para cada clave 'x', asigna el valor correspondiente de self.json a res['json'][x]
15            res['json'][x] = self.json[x]
16        # Devuelve el nuevo diccionario 'res'
17        return res

Considere agregar las claves necesarias según los elementos que defina en la estructura de su reporte. Por ejemplo:

 1    def __init__(self):
 2        # Estructura de datos predefinida
 3        self.json = {
 4            "firstElement":{
 5                "data": [],
 6            },
 7            "secondElement":{
 8                "data": [],
 9            },
10            "thirdElement":[],
11        }

Prudencia

Se dice que la clase ReportModel() es opcional, ya que se utiliza si aplica algún tipo de formateo a la data obtenida.

Función get_date_query#

Cuando un registro se almacena en los servidores de Linkaform, se utiliza la zona horaria UTC+0 (GMT) . Por ejemplo, si envía su registro el lunes 8 de enero a las 6:42 pm, el registro se almacenará considerando la zona horaria UTC+0, es decir, el martes 9 de enero a las 12:42 am.

Por este motivo, se utiliza la función get_date_query(), para convertir la fecha y hora a la zona horaria de donde se encuentran los servidores de Linkaform. Esta función se encarga de construir y retornar un diccionario que representa una consulta basada en los parámetros date_from y date_to.

Prudencia

Esta función ya está lista para su uso. Si pertenece a una zona horaria diferente o si así lo requiere, modifique la configuración de la misma (timezone). Por favor, lea los comentarios.

 1def get_date_query(date_from, date_to):
 2    # Inicializa un diccionario vacío para almacenar las condiciones de fecha
 3    res = {}
 4    # Define la zona horaria
 5    timezone = pytz.timezone('America/Monterrey')
 6    # Convierte la fecha de 'date_from' a un objeto datetime y ajusta a la zona horaria UTC
 7    tz_date =  datetime.strptime('%s 00:00:00'%(date_from), "%Y-%m-%d %H:%M:%S")
 8    tz_date = tz_date.replace(tzinfo=pytz.utc)
 9    # Convierte a la zona horaria 'America/Monterrey' y normaliza el objeto de fecha
10    tz_date = tz_date.astimezone(timezone)
11    tz_date = timezone.normalize(tz_date)
12    # Calcula el offset de la zona horaria en segundos
13    tz_offset = tz_date.utcoffset().total_seconds()
14
15    # Ajusta las fechas 'date_from' y 'date_to' restando el offset de la zona horaria
16    date_from = datetime.strptime('%s 00:00:00'%(date_from), "%Y-%m-%d %H:%M:%S") - timedelta(seconds=tz_offset)
17    date_to = datetime.strptime('%s 23:59:59'%(date_to), "%Y-%m-%d %H:%M:%S") - timedelta(seconds=tz_offset)
18
19    # Construye las condiciones de fecha en el diccionario de consulta 'res'
20    if date_from and date_to:
21        res.update({
22        'start_date': {
23        '$gte':date_from,
24        '$lt':date_to,
25        }
26        })
27    elif date_from and not date_to:
28        res.update({
29        'start_date': {
30        '$gte':date_from
31        }
32        })
33
34    elif not date_from and date_to:
35        res.update({
36        'start_date': {
37        '$lt':date_to
38        }
39        })
40    # Retorna el diccionario de condiciones de fecha
41    return res

Bibliotecas y módulos#

El primer bloque de código corresponde a las importaciones de varias bibliotecas y módulos.

Nota

Por favor, lea los comentarios dentro del código para comprender su función.

Bibliotecas y módulos#
 1# Biblioteca para trabajar con JSON (JavaScript Object Notation) en Python
 2import simplejson, sys
 3
 4# Importa el módulo "settings", "network", "utils" de la Api de Linkaform
 5from linkaform_api import settings, network, utils
 6
 7# Importa la clase "ObjectId" del módulo "bson". Esta clase se utiliza comúnmente en bases de datos NoSQL, como MongoDB, para representar identificadores únicos
 8from bson import ObjectId
 9
10# "time" se utiliza para trabajar con el tiempo, "pytz" para trabajar con zonas horarias y "math" para funciones matemáticas
11import time, pytz, math
12
13# Proporciona clases para trabajar con fechas y horas
14from datetime import datetime, timedelta, date
15
16# Importa configuraciones específicas de la cuenta
17from account_settings import *
18
19# Importa la función "normalize" del módulo "unicodedata", que se utiliza para normalizar cadenas de texto Unicode
20from unicodedata import normalize

¡Felicidades! 🎉 Si ha seguido la documentación de reportes de manera secuencial, ahora es capaz de generar sus propios reportes personalizados. Si tiene alguna duda, puede regresar al contenido o consultar la documentación oficial de la sección de su preferencia.

Si lo necesita, puede solicitar una capacitación personalizada a través del soporte técnico.