node.js: JSON dot notation + access array key - arrays

I have a site setup using node.js, express, mongoDB & mongoose. Mongoose is giving me an array that contains this:
[ { title: 'HTML in depth',
author: 'kevin vanhove',
_id: 53039f264a6324978c70084b,
chapters:
[ { _id: 53039f264a6324978c70084d,
content: '/jow',
title: 'History of HTML' },
{ _id: 53039f264a6324978c70084c,
content: '/w3c',
title: 'What is the W3C' } ],
__v: 0 } ]
I'm getting this result in my terminal using this code:
function indexData(books){
console.log(books)
res.render("index.html", {context:books, partials:{footer:"footer", header:"header"}})
}
Now i'm trying to access the value in chapters[0].title, but i'm getting an error:
console.log(books[0].chapters[0].title)
TypeError: Cannot read property '0' of undefined
I'm confused here, am i accessing the value using the right dot notation?
UPDATE 1: complete terminal output
24 Feb 10:56:47 - [nodemon] restarting due to changes...
24 Feb 10:56:47 - [nodemon] starting `node app.js`
Mongoose: books.find({}) { fields: undefined }
/Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/routes/routes.js:45
console.log(books[0].chapters[0].title)
^
TypeError: Cannot read property '0' of undefined
at indexData (/Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/routes/routes.js:45:32)
at Promise.<anonymous> (/Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/routes/routes.js:37:31)
at Promise.<anonymous> (/Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/node_modules/mongoose/node_modules/mpromise/lib/promise.js:177:8)
at Promise.EventEmitter.emit (events.js:95:17)
at Promise.emit (/Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/node_modules/mongoose/node_modules/mpromise/lib/promise.js:84:38)
at Promise.fulfill (/Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/node_modules/mongoose/node_modules/mpromise/lib/promise.js:97:20)
at /Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/node_modules/mongoose/lib/query.js:1052:26
at model.Document.init (/Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/node_modules/mongoose/lib/document.js:250:11)
at completeMany (/Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/node_modules/mongoose/lib/query.js:1050:12)
at Object.cb (/Users/kevinvanhove/Documents/work/projects/basing/business/klanten/javascript/nodeJS/express/basing/node_modules/mongoose/lib/query.js:1017:11)
24 Feb 10:56:49 - [nodemon] app crashed - waiting for file changes before starting...
Partial solution:
I was trying to get to the chapters data. Updating my mongoose schema to include the chapters data did the trick.
var booksSchema = new mongoose.Schema({
title: String,
author: String,
chapters: [
{
title: String,
content: String
}
]
});

This doesn't work an that way on the Mongoose (server) side. The result from find() is a cursor that you need to either iterate or convert via toArray from the native driver part. Something like this
(Assuming Schema Books):
Books.collection.find({}).toArray(function(err, results) {
// results is an array that you can do something with here.
});
Of course if you have defined additional Schema for arrays and their documents that are not embedded, then this is going to hurt a bit more and you need to use the iterative methods to get your results as an array.
If you want specific items from your books and sub-items within, then you would be better of tuning your find query using the operators rather than returning all results. Or even the aggregation pipeline may be of some help.

Related

Getting array value inside nested object React Redux

I have an object with an array inside it. Object is returned from MongoDB.
{
brand: "OPEL",
createdAt: "2022-12-17T17:44:31.693Z",
image: [
{
public_id: 41658465461,
url: http://www.cloudinary.com,
},
],
licensePlate: "DR126",
mileage: 526,
model: "corsa",
qrCode: "#21566",
updatedAt: "2022-12-17T17:44:31.693Z",
_id: "639dffff33060ff5c3c796eb",
}
The problem is whenever I try to get the image url in my React component obj.image[0].url it returns an error TypeError: Cannot read properties of undefined (reading '0')
console.log(obj.image[0].url) returns undefined
After refreshing page returns 2 logs:
console.log(obj.image[0].url) returns undefined
console.log(obj.image[0].url) returns "http://www.cloudinary.com" (actual link)
I assume that object is not ready before I am trying to access it.
I looked over everyone and couldn't understand where is the issue and how can I solve it.
Thank you in advance for taking a look at this !
Tried forEach() loop, found 1 solution at stackoverflow didn't do the trick in my case.
change obj.image[0].url to obj?.image[0]?.url
the ? checks if the field exists and is not undefined then access to it

discord.js slash command api loading error

I am trying to create a /config <subcommand> system for my bot, but it gives me an error with the slash command body.
Here is the current body I have for the command
name: 'config',
description: "The config system for the bot",
userPermissions: ['MANAGE_GUILD'],
options: [
{
name: 'prefix',
description: "Set a different prefifor the server",
type: "SUB_COMMAND",
options: [
{name: "new-prefix", description: "The new prefix that you want to set", type: "STRING", required: true}
]
}
]
The error is
DiscordAPIError[50035]: Invalid Form Body
0.options[0].options[0].type[NUMBER_TYPE_COERCE]: Value "STRING" is not int.
0.options[0].type[NUMBER_TYPE_COERCE]: Value "SUB_COMMAND" is not int.
I have never encountered this error before
As you are using raw json to register your commands, the type of your options must be an integer, instead of a string.
Why? Because Discord API accepts integers, not strings.
Each type has an associated id integer as documented here, which is what you have to use instead of strings.
In your case, type: "SUB_COMMAND" should be type: 1
Why options types are documented as strings in the discord.js docs? Because they made it strings to improve code readability. The lib does "convert" these strings to int before requesting the API. But you are using raw json in this case.
You can check for other application commands options type in Discord Developer Documentation

Meteor inserting into a collection schema with array elements

Hi I created a SimpleSchema for a Mongo collection which has a variable number of sub-documents called measurables. Unfortunately it's been a while since I've done this and I can't remember how to insert into this type of schema! Can someone help me out?
The schema is as follows:
const ExerciseTemplates = new Mongo.Collection('ExerciseTemplates');
const ExerciseTemplateSchema = new SimpleSchema({
name: {
type: String,
label: 'name',
},
description: {
type: String,
label: 'description',
},
createdAt: {
type: Date,
label: 'date',
},
measurables: {
type: Array,
minCount: 1,
},
'measurables.$': Object,
'measurables.$.name': String,
'measurables.$.unit': String,
});
ExerciseTemplates.attachSchema(ExerciseTemplateSchema);
The method is:
Meteor.methods({
addNewExerciseTemplate(name, description, measurables) {
ExerciseTemplates.insert({
name,
description,
createdAt: new Date(),
measurables,
});
},
});
The data sent by my form for measurables is an array of objects.
The SimpleSchema docs seem to be out of date. If I use the example they show with measurables: type: [Object] for an array of objects. I get an error that the the type can't be an array and I should set it to Array.
Any suggestions would be awesome!!
Many thanks in advance!
edit:
The measurable variable contains the following data:
[{name: weight, unit: kg}]
With the schema above I get no error at all, it is silent as if it was successful, but when I check the db via CLI I have no collections. Am I doing something really stupid? When I create a new meteor app, it creates a Mongo db for me I assume - I'm not forgetting to actually create a db or something dumb?
Turns out I was stupid. The schema I posted was correct and works exactly as intended. The problem was that I defined my schema and method in a file in my imports directory, outside both client and server directories. This methods file was imported into the file with the form that calls the method, and therefore available on the client, but not imported into the server.
I guess that the method was being called on the client as a stub so I saw the console.log firing, but the method was not being called on the server therefore not hitting the db.
Good lesson for me regarding the new recommended file structure. Always import server side code in server/main.js!!! :D
Thanks for your help, thought I was going to go mad!

google cloud endpoints body array

We have a rest API that is written in Java (hosted in Wildfly). Our service is running in kubernetes (GKE). We want to leverage Cloud Endpoints to track usage and responsiveness of our API. The API is not new, we have been shipping software that interacts with it for years. It is also quite large (thousands of public methods). We have Swagger documentation for our API, and have no validation errors. When I try to deploy our Swagger using:
gcloud beta service-management deploy swagger.yaml
It is not successful. I get the following error repeated 237 times:
ERROR: unknown location: http: body field path 'body' must be a non-repeated message.
I have tracked it down to 237 methods that include a json array in a body parameter. In our API these are methods that either accept or return a list of objects.
Is there any way I can get this accepted by service-management deploy? Changing our API isn't an option, but we would really like to be able to use endpoints.
For example, this method signature:
#PUT
#Path ("/foobars/undelete")
#Consumes (MediaType.APPLICATION_JSON)
#Produces (MediaType.APPLICATION_JSON)
#ApiOperation (value = "Undelete foobars")
#ApiResponses (value =
{
#ApiResponse (
code = 200,
message = "foobars undeleted",
response = FooBar.class,
responseContainer = "List"
) , #ApiResponse (
code = 206,
message = "Not all foobars undeleted",
response = FooBar.class,
responseContainer = "List"
) , #ApiResponse (
code = 410,
message = "Not found"
) , #ApiResponse (
code = 500,
message = "Server Error"
)
})
public Response undeleteFooBars (#ApiParam (value = "FooBar ID List") List<UUID> entityIds)
generates this swagger snippet:
"/foobars/undelete":
put:
tags:
- foo
summary: Undelete FooBars
description: ''
operationId: undeleteFooBars
consumes:
- application/json
produces:
- application/json
parameters:
- in: body
name: body
description: FooBar ID List
required: false
schema:
type: array
items:
type: string
format: uuid
responses:
'200':
description: Foo Bars undeleted
schema:
type: array
items:
"$ref": "#/definitions/FooBar"
'206':
description: Not all FooBars undeleted
schema:
type: array
items:
"$ref": "#/definitions/FooBar"
'410':
description: Not found
'500':
description: Server Error
I have had the exact same problem with Endpoints, where it does not seem to think that passing an array of objects is valid as a body parameter. I worked around this by just using a generic object and a decent description. The description will not programatically fix anything, but using a generic object allows Endpoints to work and the description gives information to the consumer of the API for what is expected.
parameters:
- in: body
name: body
description: Array of FooBar objects
required: false
schema:
type: object
This seems like an oversight on the part of the Endpoints team IMHO as using an array of objects in the body fits fine within the OpenApi spec and works with tools like http://editor.swagger.io/
Edit: I should also add that it is generally bad practice to use just a raw array as a request body or response body as it can cause a contract breaking change if additional properties are desired in the future, like say a count or pagination information.
If this is an existing API and you are just documenting the existing contract, then this solution will work to get the job done, but if you are designing a new API, then a better definition would be:
parameters:
- in: body
name: body
description: All the FooBar objects
required: false
schema:
type: object
properties:
items:
type: array
items:
$ref: '#/definitions/FooBarResource'
Since this could later be extended to add additional properties like
parameters:
- in: body
name: body
description: All the FooBar objects
required: false
schema:
type: object
properties:
count:
type: integer
description: The total count of resources
callbackUrl:
type: string
description: The URL to trigger once creation is complete
items:
type: array
items:
$ref: '#/definitions/FooBarResource'
description: The resources to create
You can do better than a plain object. Yyou can specify an array as the the value of an object with a single key. This way you preserve your type information:
parameters:
- description: "Your items to add"
in: body
name: listings
required: true
schema:
type: object
properties:
payload:
type: array
maxItems: 1000
minItems: 1
$ref: "#/definitions/listing"
It's ugly but at least it documents whatever the model you are passing in should look like.

Orionjs collection : Expected object, got undefined

I'm experiencing little trouble getting Orionjs working within Angular-Meteor especially with the collections.
I had my old mongodb declarations, for instance :
Gallery = new Mongo.Collection('gallery') and so one.
As the documentation told , I wrote
Gallery = new orion.collection('gallery') but what I get is
Error: Match error: Expected object, got undefined
at exports.check (packages/check/match.js:34:1)
at new orion.collection (packages/orionjs:collections/new.js:8:3)
at meteorInstall.shared.collections.js (shared/collections.js:1:11)
So I tried to start a project from scratch with this framework.
Fact is, it doesn't work neither with Iron Router nor Flow Router.
Can anyone hit me with any hint about it?
Thank you guys.
Ideally OrionJS expect a schema detail like the label for singular and plural names, navigation detail, table layout for displaying data and so on.Here's a typical company collection shown below:
Company = new orion.collection('company', {
singularName: orion.helpers.getTranslation('company.singularName'),
pluralName: orion.helpers.getTranslation('company.pluralName'),
title: orion.helpers.getTranslation('company.title'),
link: {
title: orion.helpers.getTranslation('company.title'),
parent: 'collections-abc'
},
tabular: {
columns: [
{ data: '_id', title: orion.helpers.getTranslation('company.schema.id') },
{ data: 'name', title: orion.helpers.getTranslation('company.schema.name') }
]
}
});
You can also pass a null JSON if you do not wish to show page directly. Usually it expects a JSON like the one shown above.

Resources