Mongoose findById - node.js

I am trying desperately to find a object stored with mongodb, with nodejs and mongoose.
The model of the object looks like:
const SimpleResourceSchema = new mongoose.Schema(
{
_id: String,
title: String,
objective: String,
url: String,
content: String,
active: Boolean,
type: String,
owner: String,
},
{
timestamps: true,
// _id: false,
}
);
export const SimpleResourceModel = mongoose.model<
SimpleResource & mongoose.Document
>('simpleResource', SimpleResourceSchema);
The query is made with 'id' parameter value '5f1da9737917360dd038bfc0':
return await SimpleResourceModel.findById(id).exec();
The data stored in mongodb is:
{
"_id": {
"$oid": "5f1da9737917360dd038bfc0"
},
"title": "Learn cooking",
"objective": "<p>Is the fridge empty ?</p>",
"content": "...",
"url": "..",
"active": true,
"type": "simple",
"owner": "5efceb2f63b75c1750846b0a",
"createdAt": {
"$date": "2020-07-26T16:04:03.806Z"
},
"updatedAt": {
"$date": "2020-07-26T16:04:03.806Z"
},
"__v": 0
}
I have looked around to get a solution, but have not found any solution to this roadblock.
Anyone can help ?

The main issue that when you define the schema you defined the id as string remove _id: String from schema definition. and it automatic be added.
If you want to add _id to typescript you can create interface
export interface SimpleResource extends Document {
_id: schema.Types.ObjectId,
...
}
then in model you directly add it but _id already defined in Document interface
and make sure that you install #types/mongoose
export const SimpleResourceModel = mongoose.model<SimpleResource>('simpleResource', SimpleResourceSchema);

Have you tried?
var ObjectId = require('mongoose').Types.ObjectId;
return await SimpleResourceModel.findById(new ObjectId(id)).exec();

i still get a null response when I try:
await SimpleResourceModel.findById(mongoose.Types.ObjectId(id)).exec()

Related

How to sync the schema change for old document collection in mongodb with default values

How can I apply the schema changes to sync with default value to all the old data in mongodb
import mongoose from "mongoose";
interface ITodo {
title: string;
description: string;
by: string;
}
interface todoModelInterface extends mongoose.Model<TodoDoc> {
build(attr: ITodo): TodoDoc;
}
interface TodoDoc extends mongoose.Document {
title: string;
description: string;
by: string;
}
const todoSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
by: {
type: String,
required: true,
},
});
todoSchema.statics.build = (attr: ITodo) => {
return new Todo(attr);
};
const Todo = mongoose.model<TodoDoc, todoModelInterface>("Todo", todoSchema);
Todo.build({
title: "some title",
description: "some description",
by: "special",
});
Todo.collection.dropIndexes(function () {
Todo.collection.reIndex(function (finished) {
console.log("finished re indexing");
});
});
Todo.collection
.getIndexes()
.then((indexes: any) => {
console.log("indexes:", indexes);
})
.catch(console.error);
export { Todo };
Db:
[{
"_id": {
"$oid": "62cee1eea60e181e412cb0a2"
},
"title": "one",
"description": "one desc"
},{
"_id": {
"$oid": "62cee2bd44026b1f85464d41"
},
"title": "one",
"description": "one desc",
"by": "alphs"
},{
"_id": {
"$oid": "62cee3c8cf1592205dacda3e"
},
"title": "one",
"description": "one desc",
"by": "alphs"
}]
Here the old data still missing the "by" key, similarly if there is nested schema change it may impact the old users, how can we define the default collection for old data in mongodb at runtime without using update query migration?
Have you tried setting the default value for "by". By giving a default value, if the old data is missing a value then the default will kick in and return the default value provided. Read about Mongoose Default: Here. I don't know if this is a good practice but we also use this method when there is change in schema and don't want to run update query.

Mongoose populate 3 deep nested schema with JSON response

I have a find() query that when executed, I can see the json with the nested schemas that I want to see except for the 'artista' attribute only displays the id, instead of the properties I want. See below:
{
"total": 1,
"ordenes": [
{
"artpieces": [
{
"_id": "60c1388f30316c02b9f6351f",
"artista": "60c055736c7ca511055a0e1a",
"nombre": "LILIES"
},
{
"_id": "60c12fca30316c02b9f63519",
"nombre": "GERNICA",
"artista": "60c136bf30316c02b9f6351b"
}
],
"_id": "60c414f9ea108a14ef75a9fb",
"precio": 3000,
"usuario": {
"_id": "609c0068e67e68",
"nombre": "Arturo Filio"
}
}
]
}
The query I use to get the json above:
const [total, ordenes] = await Promise.all([
Orden.countDocuments(),
Orden.find()
.populate("usuario", "nombre")
.populate("artpieces", ["nombre","artista","nombre"])
]);
res.json({
total,
ordenes
});
It's an order schema that has artpieces. Each artpiece (I called it 'producto'), has a name a genre, an author/artist and the user which the order belongs to.
my Schema for the orden.js:
const { Schema, model } = require('mongoose');
const OrdenSchema = Schema({
artpieces: [
{
type: Schema.Types.ObjectId,
required: true,
ref: 'Producto'
}
],
estado: {
type: Boolean,
default: true,
required: true
},
usuario: {
type: Schema.Types.ObjectId,
ref: 'Usuario',
required: true
},
precio: {
type: Number,
required: true
}
})
OrdenSchema.methods.toJSON = function () {
const { __v, estado, ...data} = this.toObject();
return data;
}
module.exports = model('Orden', OrdenSchema);
Last thing I want to mention, I know for a fact that I have the code necessary in the artista.js model to display the name of the artist because I have a similar query to display all the artpieces with each artpiece have a genre and an artist.
That example looks like so (to give context):
{
"total": 4,
"productos": [
{
"precio": 0,
"_id": "60c12fca30316c02b9f63519",
"nombre": "GERNICA",
"categoria": {
"_id": "60c04e3605d3c10ed10389e4",
"nombre": "NEO CUBISMO"
},
"artista": {
"_id": "60c136bf30316c02b9f6351b",
"nombre": "PICASSO"
},
"usuario": {
"_id": "609c8c0068e67e68",
"nombre": "Arturo Filio"
}
}
]
}
What am I doing wrong that I can't get my json result at the top look like the json at the bottom, where the artist attribute is?
Also just to point out, I have checked how to nest populate methods in order SO posts including the path and the ref to the Schema and still haven't been able to get the expected result.

mongoose find object into array of object

I'm new in mongoose and I'm trying to find user by code [user.test.test1.code] , any idea ?
Model :
const userSechema = new mongoose.Schema({
name: {
type: String,
required: true
},
test: [{}],
})
Data :
{
"_id": {
"$oid": "600020ab34742c2d34ae45e5"
},
"test": [{
"test1": {
"code": 11111
},
"test2": {
"code": 22222
}
}]
"name": "daniel"
}
query :
let regex = new RegExp(req.query.searchUserKey, 'i')
const users = await User.find({ $or: [{'name': regex },{'test.test1': { code : regex} }]})
-- Solution --
Thanks you guys, both answers is work for me
Is as simple as do "test.test1.code": 418816 into find query like this:
db.collection.find({
"test.test1.code": 418816
})
This query will give you all documents where exists test.test1.code with value 418816.
Note that this query return the whole document, not only the sub-document into the array. But I'm assuming by your post that a user is the document where exists the field name.
Example here
you can use $elemMatch, check the documentation
const users = await User.find(
{ test: { $elemMatch: { "test1.code": 418816 } } }
)

Update mongodb document that has multiple arrays of embedded documents using mongoose

Say i have a document that looks like this:
{
"personId": 13998272,
"address": [
{
"addressType": "HOME",
"streetNo": 21,
"addressLine1": "LORRAINE AVENUE",
"addressLine2": "EDGEWATER",
"city": "KINGSTON",
"parish": "ST ANDREW",
"country": "JAMAICA",
"qScore": 0.9,
"modifiedDate": "2019-02-17 15:24:19"
}
],
"phone": [
{
"originalNumber": "+18767842983",
"phoneNumberIFormat": "+18768514679",
"phoneNumberLFormat": "8768514679",
"qualityScore": 0.8,
"dataSource": "PERSON",
"modifiedDate": "2018-12-17 09:42:31"
}
],
"email": [
{
"emailAddress": "neilagreen78#yahoo.com",
"dataSource": "FINACLE",
"qualityScore": 0.89,
"modifiedDate": "2018-12-17 09:38:41"
}
]
}
My schema is defined in the code snippet below for reference:
const contactSchema = new mongoose.Schema({
pid: Number,
address: [
new mongoose.Schema({
addressType: String,
streetNo: String,
addressLine1: String,
addressLine2: String,
city: String,
parish: String,
country: String,
qScore: String,
modifiedDate: String
})
],
phone: [
new mongoose.Schema({
originalNumber: String,
phoneNumberIFormat: String,
phoneNumberLFormat: String,
qualityScore: Number,
dataSource: String,
modifiedDate: String
})
],
email: [
new mongoose.Schema({
emailAddress: String,
dataSource: String,
qualityScore: Number,
modifiedDate: String
})
]
});
How would update each array of embedded documents without overwriting the others?
Say a request is with and address and email object but not phone, how would I handle that?
You can try this ..
Get the structure of the contact object then the check to see what properties were sent in the req.body and build out the query accordingly.
N.B: You must have some validation to check the request body to ensure no unwanted properties are sent. You can use a package like Joi
const getContact = await contact.findOne({ id: req.params.id });
let query = { $addToSet: {} };
for (let key in req.body) {
if (getContact[key] && getContact[key] !== req.body[key])// if the field we have in req.body exists, we're gonna update it
query.$addToSet[key] = req.body[key];
}
const contact = await Customer.findOneAndUpdate(
{ pid: req.params.id },
query,
{new: true}
);
With mongoose, you can use $push to push object to array. The query will be like:
(saving an address and an email, querying on pid)
db.getCollection("contactSchema").update({"pid":1}, {$push: {email: emailToPush,
address:addressToPush}})
{"pid":1} is the pid of the object you want to update;
{$push: {email: emailToPush, address:addressToPush}} is the object you want to push on each array
Then you have to filter the body of the request with a middleware or something like that. I usually use a middleware to check if the request is correct, like:
EDIT:
const buildQuery = (requestBody) => {
let query = {$push: {}};
Object.keys(requestBody).map(key => {
query.$push[key] = requestBody[key];
});
}
This will build your query object (the second parameter of the update function).

inserting an objet with nested arrays in mongodb with moongose, nodejs

I am trying to insert an object like this in mongodb.
{
"client" : "Jhon"
"items" : [
[
"item": "whatever1",
],
[
"item": "whatever2",
]
]
}
I am using Mongoose, so i have a schema like this.
const itemSchema= new Schema({
item: { type: String, required: true },
})
const clientSchema = new Schema({
client: { type: String, required: true },
items: [itemSchema],
})
After i send the object to my nodejs server and create the document, i check the document created and "items" is an array that only contain _id: but nothing more.
I create the document like this.
createClient = (req, res) => {
console.log(req.body); // Here i check what is receiving the server.
clientModel.create(req.body).then(() => res.json('saved'));
}
In req.body, i checked that the server is receiving an object with empty arrays... is that normal? I am learning and i am new programing...
Your payload does not seem to be correct.
[ "item": "whatever1" ]
is not valid JSON and won't be parsed properly. Try changing your payload to:
{
"client": "Jhon"
"items": [
{ "item": "whatever1" },
{ "item": "whatever2" }
]
}

Resources