Tengo dos colecciones: libros y categorías. Las colecciones de categorías representan una estructura de árbol que las convierte en categorías anidadas usando padres e hijos.
El libro puede tener múltiples categorías y las almacena en una matriz.
Ejemplo: el libro tiene una categoría y quiero retirarlo y establecerlo en la categoría principal.
Así es como se rellena la colección de categorías.
db.categories.insertMany([ { _id: "Space Opera", ancestors: ["Science Fiction", "Fiction", "Science Fiction & Fantasy"], parent: ["Science Fiction"], }, { _id: "Dystopian", ancestors: ["Science Fiction", "Fiction", "Science Fiction & Fantasy"], parent: ["Science Fiction"], }, { _id: "Cyberpunk", ancestors: ["Science Fiction", "Fiction", "Science Fiction & Fantasy"], parent: ["Science Fiction"], }, { _id: "Science Fiction", ancestors: ["Fiction", "Science Fiction & Fantasy"], parent: ["Fiction", "Science Fiction & Fantasy"], }, { _id: "Fantasy", ancestors: ["Science Fiction & Fantasy"], parent: ["Science Fiction & Fantasy"], }, { _id: "Science Fiction & Fantasy", ancestors: [], parent: [], }, { _id: "Fiction", ancestors: [], parent: [], }, ]);
Además, ¿cómo consulto este y obtengo solo el valor "Ciencia ficción" (tenga en cuenta que está almacenado en una matriz)?
db.categories.find({_id : "Space Opera"}, {_id : 0, parent : 1})[0].parent // Did not work
db.categories.find({_id : "Space Opera"}, {_id : 0, parent : 1}) // find parent // result [ { "parent": [ "Science Fiction" ] } ]
db.books.update( {title : "Book1"}, {$set : {category : [**PARENT CATEGORY**]}} )
Creo que puedo usar el código anterior dentro de books.update()
Podría almacenar esto en una variable separada pero en vscode me da indefinido. Y la consulta interna no me da el valor correcto como se indicó anteriormente, pero creo que entendiste la idea.
db.books.update( {title : "Book1"}, {$set : {category : [db.categories.find({_id : "Space Opera"}, {_id : 0, parent : 1})]}} )
El padre que puede obtener con esta canalización de agregación:
db.categories.aggregate([ { $match: { _id: "Space Opera" } }, { $project: { _id: 0, parent: { $first: "$parent" } } } ])
o incluso
db.categories.aggregate([ { $match: { _id: "Space Opera" } }, { $project: { _id: 0, parent: { $first: "$parent" } } } ]).toArray().shift().parent
Para unir colecciones, debe usar el operador $lookup . Tenga en cuenta que las bases de datos NoSQL como MongoDB no están optimizadas para unirse/buscar. En la vida real deberías buscar un mejor diseño.
db.books.aggregate([ { $match: { title: "Book1" } }, { $lookup: { from: "categories", pipeline: [ { $match: { _id: "Space Opera" } }, { $project: { _id: 0, parent: { $first: "$parent" } } } ], as: "category" } }, { $set: { category: { $first: "$category.parent" } } } ])
Si desea actualizar la colección existente, debe crear un bucle para ello:
db.books.aggregate([...]).forEach(function (doc) { db.books.updateOne({ _id: doc._id }, { $set: { category: doc.category } }); })