Can't call a nested key in Mongoose and Express (undefined) - node.js

I have a Mongoose Schema that display results. I can display the result array but not what's inside.
{
"_id": {
"$oid": "5cfa15e123d2f414da760635"
},
"objectID": 21078,
"cars_getroute": "volvo-123-gt-coach-1967-1968",
"gm_url": "https://www.url.com",
"results": [
{
"marque": "Volvo",
"model": "Amazon 123 GT",
"model_year": "1967",
"price_str": "£4 982",
"price_int": 4982,
"price_currency": "£",
"sold": true,
"auction_house": "Anglia Car Auctions",
"auction_country": "Grande-Bretagne",
"auction_date": "25 août 2018",
"auction_datetime": "2018-08-25",
"auction_url": null,
"image_urls": null,
"price_int_eu": 5523
},
{
"marque": "Volvo",
"model": "Amazon 123 GT",
"model_year": "1968",
"price_str": "CHF9 000",
"price_int": 9000,
"price_currency": "CHF",
"sold": true,
"auction_house": "Oldtimer Galerie",
"auction_country": "Suisse",
"auction_date": "29 avril 2017",
"auction_datetime": "2017-04-29",
"auction_url": null,
"image_urls": "https://www.url.com/img/auctions/car/thumb/17-4-11-f8a85a227775570cdeb80ba0a437cc40.jpg",
"price_int_eu": 8309
},
{
"marque": "Volvo",
"model": "Amazon 123 GT",
"model_year": "1968",
"price_str": "Estimate £6 000 - £7 000 (unsold)",
"price_int": null,
"price_currency": null,
"sold": false,
"auction_house": "Herefordshire Vintage Auctions",
"auction_country": "Grande-Bretagne",
"auction_date": "20 octobre 2016",
"auction_datetime": "2016-10-20",
"auction_url": "http://www.url.com/Motor_details.php?pid=188&motor=188_01.jpg",
"image_urls": "https://www.url.com/img/auctions/car/2016-10-4a5a09eeb5c685e053e421c45656dcf7.jpg",
"price_int_eu": null
}
]
}
And the model:
const DemocarauctionSchema = new Schema({
objectID: {
type: Number
},
cars_getroute: {
type: String
},
gm_url: {
type: String
},
"results": { type: [{
marque: {
type: String
},
model: {
type: String
},
model_year: {
type: String
},
price_str: {
type: String
},
prince_int: {
type: Number
},
price_currency: {
type: String
},
sold: {
type: Boolean
},
auction_house: {
type: String
},
auction_country: {
type: String
},
auction_date: {
type: String
},
auction_datetime: {
type: String
},
auction_url: {
type: String
},
image_urls: {
type: String
},
price_int_eu: {
type: Number
},
}]}
},
{
collection: 'democarficheauction'
});
And when I call console.log(democarauctions.results.marque), nothing appears.
Is it a problem with my Schema ? Because There are multiple "marque" keys in the "results" array ?
It's working well with gm_url, objectId and cars_getroute.
EDIT: here is my Express route:
router.get('/demo/:cars_getroute', (req, res, next) => {
Promise.all([Democar.findOne({ cars_getroute: req.params.cars_getroute }), Democarauction.findOne({ cars_getroute: req.params.cars_getroute })])
.then(result => {
const [democars, democarauctions] = result;
console.log(democarauctions.results.marque)
res.render('demo/fichecar-demo', {
marque: democars.marque,
modele: democars.modele,
sous_modele: democars.sous_modele,
sous_modele2: democars.sous_modele2,
type: democars.type,
precision: democars.precision,
years_interval: democars.years_interval,
cote_actual: democars.cote_actual.toLocaleString('fr-FR'),
img_url: democars.img_url,
cote_1989_eu_excp: democars.cote.cote_1989.cote_1989_eu.cote_1989_excp,
cote_1989_eu_concours: democars.cote.cote_1989.cote_1989_eu.cote_1989_concours,
cote_1989_eu_base: democars.cote.cote_1989.cote_1989_eu.cote_1989_base,
cote_1989_eu_be: democars.cote.cote_1989.cote_1989_eu.cote_1989_be,
cote_1989_eu_me: democars.cote.cote_1989.cote_1989_eu.cote_1989_me,
cote_1989_eu_ar: democars.cote.cote_1989.cote_1989_eu.cote_1989_ar,
cote_1989_eu_epa: democars.cote.cote_1989.cote_1989_eu.cote_1989_epa,
cote_2004_excp: democars.cote.cote_2004.cote_2004_excp,
cote_2004_concours: democars.cote.cote_2004.cote_2004_concours,
cote_2004_base: democars.cote.cote_2004.cote_2004_base,
cote_2004_be: democars.cote.cote_2004.cote_2004_be,
cote_2004_me: democars.cote.cote_2004.cote_2004_me,
cote_2004_ar: democars.cote.cote_2004.cote_2004_ar,
cote_2004_epa: democars.cote.cote_2004.cote_2004_epa,
cote_2014_excp: democars.cote.cote_2014.cote_2014_excp,
cote_2014_concours: democars.cote.cote_2014.cote_2014_concours,
cote_2014_base: democars.cote.cote_2014.cote_2014_base,
cote_2014_be: democars.cote.cote_2014.cote_2014_be,
cote_2014_me: democars.cote.cote_2014.cote_2014_me,
cote_2014_ar: democars.cote.cote_2014.cote_2014_ar,
cote_2014_epa: democars.cote.cote_2014.cote_2014_epa,
cote_2017_excp: democars.cote.cote_2017.cote_2017_excp,
cote_2017_concours: democars.cote.cote_2017.cote_2017_concours,
cote_2017_base: democars.cote.cote_2017.cote_2017_base,
cote_2017_be: democars.cote.cote_2017.cote_2017_be,
cote_2017_me: democars.cote.cote_2017.cote_2017_me,
cote_2017_ar: democars.cote.cote_2017.cote_2017_ar,
cote_2017_epa: democars.cote.cote_2017.cote_2017_epa,
cote_2019_excp: democars.cote.cote_2019.cote_2019_excp,
cote_2019_concours: democars.cote.cote_2019.cote_2019_concours,
cote_2019_base: democars.cote.cote_2019.cote_2019_base,
cote_2019_be: democars.cote.cote_2019.cote_2019_be,
cote_2019_me: democars.cote.cote_2019.cote_2019_me,
cote_2019_ar: democars.cote.cote_2019.cote_2019_ar,
cote_2019_epa: democars.cote.cote_2019.cote_2019_epa,
cote_actual_chart: democars.cote_actual,
cote_actual_excp: democars.cote.cote_2019.cote_2019_excp.toLocaleString('fr-FR'),
cote_actual_concours: democars.cote.cote_2019.cote_2019_concours.toLocaleString('fr-FR'),
cote_actual_base: democars.cote.cote_2019.cote_2019_base.toLocaleString('fr-FR'),
cote_actual_be: democars.cote.cote_2019.cote_2019_be.toLocaleString('fr-FR'),
cote_actual_me: democars.cote.cote_2019.cote_2019_me.toLocaleString('fr-FR'),
cote_actual_ar: democars.cote.cote_2019.cote_2019_ar.toLocaleString('fr-FR'),
cote_actual_epa: democars.cote.cote_2019.cote_2019_epa.toLocaleString('fr-FR'),
perfo_1989: democars.performance.perfo1989,
perfo_2004: democars.performance.perfo2004,
perfo_2014: democars.performance.perfo2014,
perfo_2017: democars.performance.perfo2017,
results: democarauctions.results,
marqueauction: democarauctions.results.marque
}
});
})
.catch(err => {
// handle error.
console.log(err);
})
});
Here is my HTML template:
<div class="results__container--content">
{{#each results}}
<div class="results__container--box">
<h1>{{marqueauction}}</h1>
</div>
{{else}}
<div class="results__container--box">
<p>Aucun résultat d'enchères n'est disponible pour ce modèle.</p>
</div>
{{/each}}
</div>

results is an array, you should loop over the array to get the value of marque
let marqueauction = [];
for(let i =0; i < democarauctions.results.length; i++) {
marqueauction.push(democarauctions.results[i].marque)
}
res.render('demo/fichecar-demo', {
marqueauction: marqueauction
});
You can now render the marque in your HTML by looping over the marqueauction.

Related

ts mongoose query specific string attribute as string array (not object array)

I have this mongoose schema, and I want to query all IP attributes as a string array.
like [IP,IP,IP,IP] this, not [ { ip : ip} ]
const proxyIpSchema = new Schema<IProxyIp>({
ip: {
type: String,
required: true,
//ignore duplicate ip
unique: true,
},
port: {
type: Number,
required: false,
default: null
},
reason: {
type: String,
required: true,
default: 'Unknown Detection.'
}
},
{
timestamps: true,
}
);
I cant use a map function because it will eat the backend processing power. like this
I want all ips as a string array
//get all ips from mongo db and push to redis
await ProxyIp.find({}, { ip: 1 }).then(async (docs) => {
docs.map(async (doc) => {
await this.RedisClient?.sAdd(redisTable, doc.ip);
});
}).catch((err) => {
});
Here's one way you can put all the "ip"s into a single array (within an object).
db.ProxyIp.aggregate([
{
"$group": {
"_id": null,
"ips": {
"$push": "$ip"
}
}
},
{
"$unset": "_id"
}
])
Example output:
[
{
"ips": [
"102.118.108.76",
"34.234.240.83",
"123.76.73.33",
"134.81.197.85",
"193.122.45.195",
"54.25.18.14",
"185.68.124.193",
"3.105.130.68",
"52.72.204.78",
"117.212.118.167",
"199.155.140.226",
"64.194.68.59",
"57.4.147.57",
"190.116.4.243",
"179.111.74.98",
...
]
}
[
Try it on mongoplayground.net.

Mongoose aggregation With GraphQL returning error

I'm working on a project and currently using Mongodb Time-Series and aggregation.
I connected my Apollo Graphql to retrieve the data but i'm stuck with an error that i can not solve no matter what.
Float cannot represent non numeric value:
On my db the numbers are saved as Double. If i try to run the query in MongoDB Aggregation with MongoDBCompass it's working perfectly but not on my Nodejs database.
I tried googling my problem first and looking ad docs but all the different solution i found do not solve my problem, any suggestions?
This is my Query:
module.exports = async (root, { limit }, { models }) => {
const keyx = await models.Weather.aggregate([
{
$group: {
_id: {
yearMonthDay: {
$dateToString: { format: "%Y-%m-%d", date: "$timestamp" },
},
},
temp: {
$push: { temp: "$temp" },
},
},
},
])
.exec();
return keyx;
};
This is my model:
const mongoose = require("mongoose");
const { Schema } = mongoose;
mongoose.pluralize(null);
const weather = new Schema({
timestamp: {
type: String,
trim: true,
},
temp: {
type: Number,
trim: true,
},
});
const Weather = mongoose.model("time_weather", weather);
module.exports = { Weather };
and this is my types:
const { gql } = require("apollo-server");
module.exports = gql`
type Weather {
timestamp: String
_id: ID
temp: Float
}
type Query {
weather(limit: Int): [Weather]
}
`;
and finally this is the response i'm getting from apollo studio:
{
"errors": [
{
"message": "Float cannot represent non numeric value: [{ temp: 11.7 }, { temp: 11.7 }, { temp: 12.01 }, { temp: 13.21 }, { temp: 13.21 }, { temp: 11.93 }, { temp: 13.21 }, { temp: 12.73 }, { temp: 14.21 }, { temp: 11.7 }, ... 14 more items]",
"locations": [
{
"line": 6,
"column": 5
}
],
"path": [
"weather",
0,
"temp"
],
}
},

How to set "seen:true" in array of messages in mongoose

I am newbie in mongodb world, i was stuck in on Mongoose query.
basically I was developing a chat application for my website. the chat schema of my website shown below
const LiveChat = mongoose.Schema({
members: [String],
messages: [{
sender: String,
reciever: String,
text: String,
seen: {
type: Boolean,
default: false
},
date: {
type: Date,
default: Date.now
}
}],
}, { timestamps: true });
for exapmle collection will looks like this
[
{
"_id":"627749f8dc5927d660f76172",
"members":[
"626a250d11ed1b096883aed1",
"626a234611ed1b096883ae13"
],
"messages":[
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"626a234611ed1b096883ae13",
"text":"hello there!.",
"seen":false,
"_id":"6278b0c38031894a9ceefeae",
"date":"2022-05-09T06:12:19.857Z"
},
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"626a234611ed1b096883ae13",
"text":"how are you?.",
"seen":false,
"_id":"6278b0e18031894a9ceefede",
"date":"2022-05-09T06:12:49.680Z"
},
{
"sender":"626a234611ed1b096883ae13",
"reciever":"626a250d11ed1b096883aed1",
"text":"hello Rupesh",
"seen":false,
"_id":"6278b1438031894a9ceeff98",
"date":"2022-05-09T06:14:27.388Z"
},
{
"sender":"626a234611ed1b096883ae13",
"reciever":"626a250d11ed1b096883aed1",
"text":"we are doing well",
"seen":false,
"_id":"6278b1588031894a9ceeffe0",
"date":"2022-05-09T06:14:48.203Z"
},
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"626a234611ed1b096883ae13",
"text":"okay",
"seen":false,
"_id":"6278b1ed8031894a9cef0099",
"date":"2022-05-09T06:17:17.421Z"
}
],
"createdAt":"2022-05-08T04:41:28.416Z",
"updatedAt":"2022-05-09T06:17:17.420Z",
"__v":0
},
{
"_id":"62762021be68a5e2de8dc2d2",
members: ["626a250d11ed1b096883aed1", "6273bc879ff276ac89f9c4f8"]
"messages":[
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"6273bc879ff276ac89f9c4f8",
"text":"hello there!",
"seen":false,
"_id":"6277ac0ba5fe501f98e1421e",
"date":"2022-05-08T11:39:55.263Z"
},
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"6273bc879ff276ac89f9c4f8",
"text":"can you please tell me what is the date of start a project task",
"seen":false,
"_id":"6277ac30a5fe501f98e1424c",
"date":"2022-05-08T11:40:32.472Z"
},
],
"createdAt":"2022-05-07T07:30:41.447Z",
"updatedAt":"2022-05-08T12:24:31.400Z",
"__v":0
}
]
now i want to set seen:true for all messages into messages array whose sender == "626a250d11ed1b096883aed1" ( sender_id and conversation_id are given from req.body into a API).
for all messages in messages array:
seen:false means message is not seen by reciever
seen:true means message is seen by reciever
i was trying following way into my express API but its not wokring...
cosnt {conversation_id, sender_id} = req.body;
LiveChat.findByIdAndUpdate({ _id: conversation_id },
[{
$set: {
'messages.seen': { $cond: [{ $eq: ['messages.sender', sender_id] }, true, false] }
}
}]
,
{
new: true,
useFindAndModify: true,
}
please help me to write this query...
Here's one way you could do the update using "arrayFilters".
db.collection.update({
"_id": "627749f8dc5927d660f76172" // given _id
},
{
"$set": {
"messages.$[x].seen": true
}
},
{
"arrayFilters": [
{
"x.sender": "626a250d11ed1b096883aed1" // given sender
}
]
})
Try it on mongoplayground.net.

Get all data from subdocument via graphql

Model
const mongoose=require('mongoose');
const CustomerGeneralInformation = require('./CustomerGeneralInformation').schema;
const CustomerContact = require('./CustomerContact').schema;
const CustomerFinance=require('./CustomerFinancial').schema;
const CustomerPersonalData=require('./CustomerPersonalData').schema;
const CustomerIdentification=require('./CustomerIdentification').schema;
const Schema=mongoose.Schema;
const CustomerSchema=new Schema({
generalInformation: [CustomerGeneralInformation],
contactData: [CustomerContact],
financialData:[CustomerFinance],
personalData:[CustomerPersonalData],
identificationData:[CustomerIdentification]
});
module.exports=mongoose.model('Customer',CustomerSchema);
Graphql Schema
const RootQuery=new GraphQLObjectType({
name:'RootQueryType',
fields:{
customers:{
type: new GraphQLList(CustomerType),
resolve(parent,args){
return customer.find({});
}
}
}
});
GraphiQl
{
customers
{
id
generalInformation{
purposeOfBusiness
}
contactData{
phone
email
countryResidence
mailbox
houseNo
zip
city
}
financialData{
taxNo
countryTaxation
refBankIban
StringrefBankBic
refBankIban
}
}
}
Result
{
"data": {
"customers": [
{
"id": "5fa0f8ea4e028a2cf8d24c3f",
"generalInformation": {
"purposeOfBusiness": null
},
"contactData": {
"phone": null,
"email": null,
"countryResidence": null,
"mailbox": null,
"houseNo": null,
"zip": null,
"city": null
},
"financialData": {
"taxNo": null,
"countryTaxation": null,
"refBankIban": null,
"StringrefBankBic": null
}
}
]
}
}
SO I have created a customer model which have an id(autogenerated by mongodb) and 5 other fields of schema type.
I have used graphql for creating apis.
Everything is working fine, I have created mutations to add data, its all tested in mongo that data is being saved.
But if you check my graphql output I am unable to query subdocuments, it shows null. I want list of all subdocuments with data.
PlEASE HELP
I had tried this way and its working perfectly,
Firstly as you are passing the whole model in your new Customer model so instead of that I just have stored the ID as a reference.
const CustomerSchema = new mongoose.Schema(
{
generalInformation: {
type: mongoose.Schema.Types.ObjectId,
ref: "GeneralInfo"
},
contactData: { type: mongoose.Schema.Types.ObjectId, ref: "ContactData" },
financialData: {
type: mongoose.Schema.Types.ObjectId,
ref: "FinacialData"
},
personalData: { type: mongoose.Schema.Types.ObjectId, ref: "PersonalData" }
},
{
timestamps: true
}
);
After that, for CustomerType, I had done this
const CustomerType = new GraphQLObjectType({
name: "Customer",
fields: () => ({
id: { type: GraphQLID },
customerContact: {
type: CustomerContactType,
resolve(parent, args) {
return CustomerContact.findById(parent.contactData);
}
},
generalInformation: {
type: CustomerGeneralType,
resolve(parent, args) {
return CustomerGeneral.findById(parent.generalInformation);
}
},
financialData: {
type: CustomerFinanceType,
resolve(parent, args) {
return CustomerFinance.findById(parent.financialData);
}
},
personalData: {
type: CustomerPersonalType,
resolve(parent, args) {
return CustomerPersonal.findById(parent.personalData);
}
}
})
});
And them for RootQuery
customers: {
type: new GraphQLList(CustomerType),
resolve(parent, args) {
return Customar.find({});
}
}
and here is my Query:
{
customers{
id
generalInformation{
purposeOfBusiness
}
customerContact{
phone
email
countryResidence
}
financialData{
taxNo
}
}
}
And Output
{
"data": {
"customers": [
{
"id": "5fa3fe066f0fda0568e56456",
"generalInformation": {
"purposeOfBusiness": "Test Purpose"
},
"customerContact": {
"phone": "123456798",
"email": "test#demo.com",
"countryResidence": "Pak"
},
"financialData": {
"taxNo": "120033244"
}
}
]
}
}

Data null after saving entity with Moongose and GraphQL

When saving an entity with mongoose and graphql the following happens:
First method to save:
create(budgetProps){
const budget = new Budget(budgetProps);
return budget.save();
}
The result is as follows:
{
"data": {
"addBudget": {
"_id": "59fbdefaa7b0a81180dd2c9c",
"tiempoAproximado": 2245.5,
"User": {
"name": null,
"organization": null
},
"Vehicle": {
"name": null,
"type": null
}
}
}
}
Using this method:
create(budgetProps){
const budget = new Budget(budgetProps);
return budget.save().then((res)=>{
Budget.findById(res._id)
.populate('User')
.populate('Vehicle')
.exec((err, newBudget)=> {
return newBudget;
});
});
},
I get the following:
{
"data": {
"addBudget": null
}
}
This is the Schema:
const typeDefs = `
scalar Date
input UserInput {
_id: ID,
name: String,
organization: String,
phones: [String],
emails: [String],
type: String,
password: String,
percentaje: String
}
input VehicleDescriptionInput {
es: String,
en: String
}
input VehicleInput{
_id: ID,
name: String,
passengers: Int,
largeBags: Int,
smallBags: Int,
doors: Int,
type: String,
status: Boolean,
imagesUrls: [String],
description: VehicleDescriptionInput
}
input FinalTotalCostInput {
es: String,
en: String
}
input BudgetTotalCostInput {
es: String,
en: String
}
input BudgetInput {
finalTotalCost: FinalTotalCostInput,
budgetTotalCost: BudgetTotalCostInput,
destinoInicial: String,
destinoFinal: String,
tiempoAproximado: Float,
distancia: Float,
tollCost: Float,
tolls: [String],
budgetDate: Date,
aprove: Boolean,
User: UserInput,
Vehicle: VehicleInput
}
type Mutation {
addBudget(data: BudgetInput): Budget
}
`;
Here is the resolver:
Mutation: {
addBudget: (_, {data}) =>{
return BudgetController.create(data);
}
},
Finally here is the mutation with its variables:
mutation addBudget($budget: BudgetInput) {
addBudget(data: $budget) {
_id
User{
name
organization
}
Vehicle{
name
type
}
}
}
{
"budget": {
"finalTotalCost": {
"es": "100 peso",
"en": "10 dolars"
},
"budgetTotalCost": {
"es": "80 peso",
"en": "8 dolars"
},
"destinoInicial": "Queretaro",
"destinoFinal": "Sonora",
"tiempoAproximado": 2245.5,
"distancia": 100.565,
"tollCost": 20.5,
"tolls": [
"GDL",
"Marina",
"Culap",
"Malageña"
],
"budgetDate": "2017/07/21",
"aprove": false,
"User": {
"_id": "59fbcc42aa82460924e5fbad"
},
"Vehicle": {
"_id": "59fbcbe4aa82460924e5fbac"
}
}
}
The entity is stored properly in the database, when Console.log the result of the populated search results are correct then I do not understand what is happening.
You can find the whole app in the following link: GitHub Repo
You're mixing Promises and callbacks. exec() will return a Promise, but only if doesn't have any arguments passed to it. Additionally, you need to return the Promise that's returned by exec().
return budget.save().then((res) => {
return Budget.findById(res._id) // missing return here
.populate('User')
.populate('Vehicle')
.exec() // don't need anything else
})
You can clean this up a little more:
return budget.save()
.then(res => Budget.findById(res._id)
.populate('User')
.populate('Vehicle')
.exec())
If you need to transform the results returned by findById before turning them over to the client:
return budget.save()
.then(res => Budget.findById(res._id)
.populate('User')
.populate('Vehicle')
.exec())
.then(res => {
res.foo = 'Foo'
return res
})

Resources