I am implementing full text search engine in my personal collection app in which there users, collections and items. When user searches , if even it is a comment inside item , it should be displayed. So i tried with text string of mongoose but it is working only with seperate schemas . Ex: only in collection schema or in items schema. I want to create only one route in which i should be able to search everything inside items and collection, even comments inside items. Here is what i have for now but it is giving me only collections property not referecned items schema details:
Collection schema
const collectionSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
image: { type: String },
customFields: [{ type: Object }],
owner: { type: Schema.Types.ObjectId, ref: "User" },
items: [{ type: Schema.Types.ObjectId, require: true, ref: "Item" }],
},
{ timestamps: true }
);
Collection Route
collectionRoute.get("/search", async (req, res, next) => {
try {
const { title } = req.query;
const searchitem = await CollectionModal.find({
$text: { $search: title },
});
res.status(200).send(searchitem);
} catch (error) {
next(error);
}
});
Related
i am creating items inside collections and in each items authors are able to leave a comment. i want retrieve comment with their author . so that i referenced author id inside comment schema and i am only getting author id when i populate author in my get request. So can anyone help to get comments with its author information?
ITEM SCHEMA
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const itemSchema = new Schema(
{
name: { type: String },
comments: [
{
owner: { type: Schema.Types.ObjectId, ref: "User" },
text: { type: String },
},
],
owner: { type: Schema.Types.ObjectId, ref: "User" },
collections: { type: Schema.Types.ObjectId, ref: "Collection" },
},
);
itemSchema.index({ "$**": "text" });
export default model("Item", itemSchema);
GET COMMENT ROUTE
itemRouter.get(
"/:itemId/comments",
JWTAuthMiddleware,
adminAndUserOnly,
async (req, res, next) => {
try {
if (req.params.itemId.length !== 24)
return next(createHttpError(400, "Invalid ID"));
const items = await ItemModal.findById(req.params.itemId).populate("owner");
if (!items)
return next(
createHttpError(
400,
`The id ${req.params.itemId} does not match any items`
)
);
res.status(200).send(items.comments);
} catch (error) {
next(error);
}
}
);
What i am getting is only user id and comment
i am trying to create items to specific id of collection using nodejs and mongoose but i am getting CastError which i shared below picture. So goal is, I binded items id in collection schema because collection has many items and when i create items to the specific id of collection i want to push them to items array in the collection schema.
ERROR
ITEMS ROUTE
itemRouter.post("/:collectionId", JWTAuthMiddleware, async (req, res, next) => {
const {name} = req.body
if (req.params.collectionId.length !== 24)
return next(createHttpError(400, "Invalid ID"));
const collection = await CollectionModal.findByIdAndUpdate(
req.params.collectionId,
{
$push : { items: { ...req.body, owner: req.user._id, id: uuidv4() } },
},
{ new: true }
);
if (!collection)
return next(
createHttpError(
400,
`The id ${req.params.collectionId} does not match any collections`
)
);
res.send(collection);
});
Collection schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const collectionSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
image: { type: String },
additionalCustomFields: {
fieldNumber: { type: Number },
fieldName: { type: String },
fieldType: { type: String },
fieldChecked: { type: Boolean },
fieldDate: { type: Date },
},
owner: { type: Schema.Types.ObjectId, ref: "User" },
items: [{ type: Schema.Types.ObjectId, ref: "Item" }],
},
{ timestamps: true }
);
// collectionSchema.index({ "$**": "text" });
export default model("Collection", collectionSchema);
ITEM schema
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const itemSchema = new Schema(
{
name: { type: String },
description: { type: String },
topic: { type: String },
image: { type: String },
comments: [
{
user: { type: Schema.Types.ObjectId, ref: "User", required: true },
text: { type: String },
},
],
tags: { type: String },
owner: { type: Schema.Types.ObjectId, ref: "User" },
likes: [{ type: Schema.Types.ObjectId, ref: "User" }],
collections: { type: Schema.Types.ObjectId, ref: "Collection" },
},
{ timestamps: true }
);
itemSchema.index({ "$**": "text" });
export default model("Item", itemSchema);
Are you sure that using referenced documents is the correct way to go here? Mongoose is complaining because you are trying to push whole objects to the "items" array, instead of ObjectIds of referenced documents.
You have 2 choices here:
1. use embedded documents
This way you can easily store objects directly to the items array, which does not allow you to store the Items in a seperate collection
2. first create Item documents, then push the reference to items array
In this case you have to first create the items in Item collection. Afterwards you can map the result to only ObjectIds and push these to items array of your collection document.
I have two collections in mongodb "components" and "airframes" which I am trying to join together (with a one to many relationship). I have the following code which gets the airframe and component data separately from the database, however after days of effort, I cannot figure out how to join the two together. I assume I need to use $lookup to achieve the desired result but any assistance in constructing the code would be greatly appreciated.
my models are as follows and I am trying to join all the component records under the associated Airframe. the airframe field on the Component holds the related Airframes' id.
const airframeSchema = mongoose.Schema({
name: { type: String, required: true },
sNumber: { type: String, required: true },
aStatus: { type: String, required: true },
components: [ {
type: mongoose.Schema.Types.ObjectId,
ref: 'Component' } ]
});
module.exports = mongoose.model('Airframe', airframeSchema);
const componentSchema = mongoose.Schema({
name: { type: String, required: true },
serial: { type: String, required: true },
type: { type: String, required: true },
airFrame: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Airframe'},
});
module.exports = mongoose.model('Component', componentSchema);
the AirFramesService is as follow. I would like to join the component data under a array called "component".
getAirframes() {
this.http
.get<{ message: string; airframes: any }>("http://3.135.49.46:8080/api/airframes")
.pipe(
map(airframeData => {
return airframeData.airframes.map(airframe => {
return {
name: airframe.name,
sNumber: airframe.sNumber,
aStatus: airframe.aStatus,
id: airframe._id,
};
});
})
)
.subscribe(transformedAirframes => {
this.airframes = transformedAirframes;
this.airframesUpdated.next([...this.airframes]);
});
}
getAirframeUpdateListener() {
return this.airframesUpdated.asObservable();
}
getAirframe(id: string) {
return this.http.get<{ _id: string; name: string; sNumber: string ; aStatus: string}>(
"http://3.135.49.46:8080/api/airframes/" + id
);
}
The airframes route code is as follows:
router.get("", (req, res, next) => {
Airframe.find().then(documents => {
res.status(200).json({
message: "Airframes fetched successfully!",
airframes: documents
});
});
});
and here is the code within the ts component file that gets the airframe data is as follows.
constructor( public airframesService: AirframesService) {
this.airframesService.getAirframes();
this.airframesSub = this.airframesService.getAirframeUpdateListener()
.subscribe((airframes: Airframe[]) => {
this.isLoading = false;
this.airframes = airframes;
}, 0);
});
}
the desired outcome would be the following (at the moment I only get the airframe data):
{
_id: "123"
name: "Airframe01"
sNumber: "757"
aStatus: "Active"
id: "5e8052ad1fa18f1c73524664"
components: [
{
name: "Left Tank",
serial: "3456789",
type: "Landing Gear",
airFrame: "5e8052ad1fa18f1c73524664"
},
{
name: "Right Tank",
serial: "45678",
type: "Landing Gear",
airFrame: "5e8052ad1fa18f1c73524664"
}
]
}
Your document structure already established a one-to-many kinda relationship between the two models, you can use Mongoose population to get the join you described in the question. The populate code should be somewhere in the airframes route like this:
router.get("", (req, res, next) => {
// Notice the populate() method chain below
Airframe.find().populate('components').then(documents => {
// The documents output should have their "components" property populated
// with an array of components instead of just Object IDs.
res.status(200).json({
message: "Airframes fetched successfully!",
airframes: documents
});
});
});
You can read more about Mongoose population here.
I have two documents in mongodb:
export const Category = mongoose.model('Category', new mongoose.Schema({
name: { type: String },
}));
export const SubCategory = mongoose.model('SubCategory', new mongoose.Schema({
name: { type: String },
category: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
}));
How to find All SubCategory that match Category by name?
I have try a lot of ways but I always getting null or error...
var name = '...';
SubCategory.find({ category: { name } });
SubCategory.find({ category: { name } }).populate('category');
You can use aggregation for the same. Please read this documentation https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/
Note:- This answer is based on your collection and data you have entered. this is not perfect but this will help best to find the logic from this answer. :-)
//collection 1 schema
const collection1Schema = new Schema({
user_id: {
type: String,
required: true
},
status: {
type: String
}
});
mongoose.model('Collection1', collection1Schema);
//collection 2 schema
const collection2Schema = new Schema({
user_id: {
type: Schema.Types.ObjectId,
ref: 'user_id'
},
item: {
type: String
}
});
mongoose.model('Collection2', collection2Schema);
//find data from collection2
Collection2.find()
.populate('user_id')
.exec(function(err, foundDocuments) {
if (error) {
console.error(err);
} else {
console.log(foundDocuments);
}
});
For more info:- Mongoose populate
I have a model called List.js that looks like this:
module.exports = function(mongoose, models) {
var collection = 'List',
Schema = mongoose.Schema;
var schema = new Schema({
promotor: String,
nombre_promotor: String,
cod_evento: {type: Schema.Types.ObjectId, ref: 'Evento'},
lista: [{
nombre: String,
cod_usuario_lider: {
type: Schema.Types.ObjectId,
ref: 'Usuario'
},
usuarios_agregados: [{
cod_usuario: {
type: Schema.Types.ObjectId,
ref: 'Usuario'
},
nombre: String,
fbid: String,
tipo_usuario: Number
}]
}]
});
this.model = mongoose.model(collection, schema);
return this;
}
Im trying to find the documents that match with cod_usuario_lider in the field "lista" and the ones that match with "cod_usuario" in "usuarios_agregados" inside "lista". The first part of the query returns the matched documents, but the second part doesnt return nothing. Anyone knows the proper way to do that query?
var codigo_buscar=req.body.codigo_buscar;
models.List.find({
$or: [{
lista: {
$elemMatch: {
cod_usuario_lider: codigo_buscar
}
}
}, {
usuarios_agregados: {
$elemMatch: {
cod_usuario: codigo_buscar
}
}
}]
})
.exec(function(err, data) {
console.log(data);
});
The first part of the query returns the matched documents, but the second part doesnt return nothing. Anyone knows the proper way to do that query?
From your document, it looks like usuarios_agregados is an attribute to lista. In that case you have to query as below:
var codigo_buscar=req.body.codigo_buscar;
models.List.find({
$or: [{
lista: {
$elemMatch: {
cod_usuario_lider: codigo_buscar
}
}
}, {
lista.usuarios_agregados: {
$elemMatch: {
cod_usuario: codigo_buscar
}
}
}]
})
.exec(function(err, data) {
console.log(data);
});