PyMongo - Query com range numa base de 17 MM de registros e update

12 views
Skip to first unread message

Rogério Carrasqueira

unread,
Jan 8, 2021, 3:32:27 PM1/8/21
to MongoDB Brasil
Olá Pessoal,

Eu tenho uma base e preciso dentro de um cliente que possui 17 MM de registros selecionar um range de 5 mil contatos, que atenda uma query dentro dessa collection.

Estou utilizando o MongoEngine e PyMongo com CursorCollection e não consigo interagir sobre o primeiro registro desse subset. Ao tentar executar o banco de dados abenda e não ocorre a interação.

Coloquei o mongo DB para rodar em uma máquina na AWS t3.xlarge e ainda assim ao executar essa query ela não roda.

A query segue abaixo:

query = {
    '$and': [{
        u 'tag_list': '33854'
    }, {
        u 'customs': {
            u '$not': {
                u '$elemMatch': {
                    u 'k': u 'rule_id',
                    u 'v': 301
                }
            }
        }
    }, {
        u 'customer_id': 4275 L
    }, {
        'status': {
            '$nin': [u 'invalid_domain', u 'inexistent_address',
                u 'mailbox_full', u 'smsfail', u 'whatsappfail'
            ]
        }
    }, {
        'customer_id': {
            '$in': [4275]
        },
        'opt_out': False
    }, {
        u 'campaigns': {
            u '$not': {
                u '$elemMatch': {
                    u 'id': 112129 L
                }
            }
        }
    }]
}

cursor = Contact._get_collection().find(query, {
    'id': 1
}).hint([('customer_id', 1), ('tag_list', 1), ('status', 1),
    ('opt_out', 1)
]).batch_size(5000).limit(5000)[1100001: 1149999]

Eu pretendo utilizar essa query para interar e fazer um updateMany, conforme rotina abaixo:

update_exec = {
      '$push': {
           'campaigns': {'id': campaign_id, 'was_sent': False, 'type':
campaign_type}
       }
}

for c in cursor:

    contact = Contact._from_son(c)

    bulk_operations.append(
         UpdateOne({
             '_id': contact.id,
             'campaigns': {
                 '$not':{
                      '$elemMatch':{
                          'id': campaign_id,
                      }
                }
            }
           }, update_exec)
    )

results = Contact._get_collection().bulk_write(bulk_operations, ordered=False)

A minha classe Contact está abaixo descrita para que vejam como ela foi estruturada:

# Create your models here.
class Contact(mongo.DynamicDocument):


    STATUS_CHOICES = (('ok', _('Ativo')),
                      ('mx', _('Falha na entrega')),
                      ('invalid_domain', _('Dominio inválido')),
                      ('inexistent_address', _('E-mail não existe')),
                      ('mailbox_full', _('Caixa cheia')),
                      ('size_limit', _('Limite da mensagem excedido')),
                      ('mail_loop', _('E-mail em loop')),
                      ('spam', _('Spam')),
                      ('unknown', _('Erro desconhecido')),
                      ('complaint', _('Reclamação')),
                      ('abuse', _('Denúncia de Abuse')),
                      ('smsfail', _('Falha na Entrega de SMS')),
                      ('whatsappfail', _('Falha na Entrega de WhatsApp')))


    customer_id = mongo.IntField(verbose_name=_(u'Cliente'),
unique_with='email')
    name = mongo.StringField(max_length=255, verbose_name=_(u'Nome'))
    email = mongo.EmailField(verbose_name=_(u'E-mail'))
    campaigns = mongo.ListField(mongo.DictField(),
verbose_name=_(u'Campanhas que o usuário participou'))
    customs = mongo.ListField(mongo.DictField(),
verbose_name=_(u'Campos customizados do cliente'))
    status = mongo.StringField(choices=STATUS_CHOICES, default='ok',
max_length='10', verbose_name=_(u'Status do E-mail'))
    date_created = mongo.DateTimeField(verbose_name=_(u'Criado em'))
    last_updated = mongo.DateTimeField(verbose_name=_(u'Última atualização em'))
    tag_list = mongo.ListField(mongo.StringField(),
verbose_name=_(u'Listas que o contato faz parte'))

    meta = {
        'index_background': True,
        'index_drop_dups': True,
        'indexes': [
            ('customer_id', 'tag_list', 'status', 'opt_out'),
            ('customer_id', 'tag_list', 'status'),
            ('customer_id', 'tag_list', 'opt_out'),
            ('customer_id', 'customs.k', 'customs.v', 'status', 'opt_out')
        ],
    }

    class Meta:
        using = 'mongodb'
        verbose_name = _(u'Contato')
        verbose_name_plural = _(u'Contatos')

Eu tentei já utilizar skip and limit e inicialmente atende, mas quando aumenta a posicao inicial mais para meio do intervalo, a query fica realmente lenta.

Tentei outras abordagens utilizando intervalo ao final da query somente com o limit, mas também não funcionou.

Agradeço de coração a ajuda dos amigos!

Grande abraço!

Rogério Carrasqueira

coisasdangelica

unread,
Sep 16, 2021, 6:20:32 AM9/16/21
to MongoDB Brasil

Bom dia Rogério!

Você conseguiu a solução?
Reply all
Reply to author
Forward
0 new messages