4
respostas

Busca por field no MongoDB/Mongoose

Fala ai pessoal, tem um tempo que não venho aqui. Nos últimos tempos estou estudando muito node e acabei caindo no maravilhoso MongoDB, acontece que aprendi muito dele mais travei em uma parte. Na busca por uma field específica, principalmente quando ela está atrelada a um Array. Bem, vamos a minha dúvida, eu basicamente tenho um JSON no Mongo:

{
    "_id": {
        "$oid": "5b37f4b5fe0cd65b1739641b"
    },
    "email": "example@me.com",
    "username": "pedro",
    "password": "$2b$10$Zpynx8wTgqQftUO3m1tLUO8lNHtBtxl0i7yk84rRkVzcTmB9zO7Mu",
    "__v": 0,
    "tds": [
        {
            "_id": {
                "$oid": "5b3d58cf073b2b88df13be8d"
            },
            "category": "Projects",
            "todos": [
                {
                    "_id": {
                        "$oid": "5b3d793bd723ea8c790d9395"
                    },
                    "todo": "Fazer alguma coisa"
                },
                {
                    "_id": {
                        "$oid": "5b3e11f95668de93c25c06c0"
                    },
                    "todo": "Fazer outra coisa"
                },
                {
                    "_id": {
                        "$oid": "5b3e1834e2b35b94fb9e644b"
                    },
                    "todo": "Fazer mais alguma coisa"
                }
            ]
        },
        {
            "_id": {
                "$oid": "5b3e158e93c0dd9442399dd7"
            },
            "category": "Principal",
            "todos": [
                {
                    "_id": {
                        "$oid": "5b3e158e93c0dd9442399dd6"
                    },
                    "todo": "Nós vamos fazer isso"
                },
                {
                    "_id": {
                        "$oid": "5b3e1895b9622995055f0082"
                    },
                    "todo": "Fazer isso nós vamos - Yoda"
                }
            ]
        }
    ]
}

Explicando: Estou fazendo um sistema de To do List (Projeto de aprendizado), o qual terá login (Até ai tudo bem, usando Authentication e Express Session, depois percebi que o ideal seria ter todos os Todo's no mesmo JSON que o User (Não sei se é o melhor a se fazer, me avisem se não é uma boa pratica), aí entra o meu problema. Tenho categorias de todo's e nessas categorias os respectivos todo's. Como faço para conseguir acessar somente o todo de id: "5b3e1895b9622995055f0082" - "todo": "Fazer isso nós vamos - Yoda"? Se eu quiser mudar esse todo? Acabou que com um código usando eu consegui atualizar de acordo com a posição do array:

User.findOneAndUpdate({"tds.todos._id":ObjectId("5b3e11f95668de93c25c06c0")},'tds.$.todos.0.todo':"Fazer outro todo",function(err,docs) {
  console.log(docs.tds);
})

Mas não adiantou nada usar o _id já que tive que indicar a posição do todo ('tds.$.todos.0.todo') Indicando o 0 como primeiro array. Bem, posso até usar isso para atualizar mas não seria a melhor forma nem a mais otimizada, sen contar que se eu quiser achar especificamente este todo eu não consigo.

Bem, muito especifica minha dúvida, espero que alguém consiga me ajudar :) tentei no stackoverflow mas a dúvida ainda está la sem resposta, aí decidi vir pra amada alura <3.

Agradeço a todos que tentarem, abraços.

Qualquer duvida em relaçao ao codigo, bem como ao

4 respostas

Oi Pedro, mas o $ não é um ponteiro para um item do array? Então em vez de usar o zero, você tentou usar ele novamente? Tipo: ('tds.$.todos.$.todo')

Sobre ser uma boa prática ou não, depende. O pessoal dos bancos relacionais separariam em duas coleções diferentes, mas o pessoal do não relacional geralmente junta tudo assim mesmo.

Olá, Pedro!

O findOneAndUpdate é melhor pra quando você quer sobreescrever o documento todo.

Será que não seria melhor:

  1. Fazer o findOne
  2. Alterar o objeto
  3. Passar o objeto atualizado com o update

O que acha?

Bem, a tentativa com tds.$.todos.$.todo nao funcionou, pelo que eu andei lendo só é possível usar o $ uma vez,.

Ja, Alexandre, poderia me explicar melhor? Devo usar o findOne, mas como? Uso o findOne para selecionar o usuario específico e após isso como faço?

Tentei usar o find do ES6, fazendo:

User.findOne({"_id": ObjectId("5b37f4b5fe0cd65b1739641b")},function(err,docs) {
    console.log(docs.tds.find((obj) => obj._id === ObjectId("5b3d58cf073b2b88df13be8d")));

})

Porém retorna undefined

Maaaaaas se eu procuro por uma categoria:

User.findOne({"_id": ObjectId("5b37f4b5fe0cd65b1739641b")},function(err,docs) { console.log(docs.tds.find((obj) => obj.category === 'Projects')); })

Eu encontro o tds específico. Bem, nao sei porque nao está funcionando.

Obrigado pela ajuda ai pessoal :)

Opa, Pedro!

Para comparar ObjectId temos que usar o .equals().

Então, ficaria assim:

User.findOne({"_id": ObjectId("5b37f4b5fe0cd65b1739641b")}, function(err,docs) {
    console.log(docs.tds.find((obj) => obj._id.equals( ObjectId("5b3d58cf073b2b88df13be8d"))));

})

Referência:

http://mongodb.github.io/node-mongodb-native/2.0/api/ObjectID.html#equals