Here is an example of creating a managed Kubernetes cluster on DigitalOcean.
import * as pulumi from "#pulumi/pulumi";
import * as digitalocean from "#pulumi/digitalocean";
const foo = new digitalocean.KubernetesCluster("foo", {
region: "nyc1",
version: "1.20.2-do.0",
nodePool: {
name: "front-end-pool",
size: "s-2vcpu-2gb",
nodeCount: 3,
},
});
Example code taken from the Pulumi DigitalOcean package documentation.
How do I retrieve the droplet node IPv4 addresses for use in say creating DnsRecord resources?
const _default = new digitalocean.Domain("default", {name: "example.com"});
// This code doesn't work because foo.nodePool is just the inputs.
const dnsRecords = foo.nodePool.nodes(node => new digitalocean.DnsRecord("www", {
domain: _default.name,
type: "A",
value: node.ipv4Address,
}));
DigitalOcean doesn't return a list of node IP addresses from the Kubernetes cluster you created. You can retrieve these values using the getDroplet function.
However, you'll need to do this iteration inside an apply() like so:
const addresses = foo.nodePool.nodes.apply(
nodes => nodes.forEach(
(node) => {
let n = digitalocean.getDropletOutput({
name: node.name
})
new digitalocean.DnsRecord("www", {
domain: domain.name,
type: "A",
value: n.ipv4Address,
})
}
)
)
Using an apply here lets us wait until the foo.nodePool.nodes has been created by the API. We can then iterate over it like a normal array, get the droplet, assign it to the variable n and then create a new DNS record for each of the nodes
Related
I'm struggling to correctly type the endpointMeta object in my project.
It contains computed object keys that are related to 2 objects
services - contains the names of the services currently known. The number of services may increase later.
endpoints - define the endpoints available in the service, that are being called in the project.
enum services {
serviceNameOne = 'service1',
serviceNameTwo = 'service2',
serviceNameThree = 'service3',
};
const endpoints = {
[services.serviceNameOne]: {
getUser: '/getUser',
verifyDetails: '/s/verifyDetails',
},
[services.serviceNameTwo]: {
fetchCustomersv1: '/v1/fetchCustomers',
fetchCustomersv2: '/v2/fetchCustomersv1',
},
[services.serviceNameThree]: {
getAllProjects: '/g/a/p',
getProject: '/g/p',
updateProject: '/u/p',
}
}
endpointMeta - object contains some meta info about these endpoints
const endpointMeta = {
[services.serviceNameOne]:{
[endpoints.serviceOne.getUser]: {
description: 'something about getUser',
version: 1
},
[endpoints.serviceOne.verifyDetails]:{
description: 'something about verifyDetails',
version: 3
},
},
[services.serviceNameTwo]:{
[endpoints.serviceTwo.fetchCustomersv1]: {
description: 'something about fetchCustomersv1',
version: 1
},
[endpoints.serviceTwo.fetchCustomersv1]:{ // duplicate object :(
description: 'something about fetchCustomersv1',
version: 1
},
}
}
Edit
What I ideally want is for when other devs are introducing new services or endpoints, they should be forced to add an entry to the endpointmeta object.
TS Playground
I have this query in my code which allows me to build a tag cloud for this blog front page
tagCloud:allContentfulBlogPost {
group(field: tags, limit: 8) {
fieldValue
}
}
It's passing data that I map in my component using {data.tagCloud.group.map(tag => (...))};. The code works nicely, but it won't be limited by the filter I'm passing above in the group(fields: tags, limit: 8) in my query. It renders all the tags and not only the first eight.
I've unsuccessfully tried the skip filter as well for the sake of seeing if it works.
Is this the proper way to limit the count to my mapping component in Gatsby?
The Contentful source plugin doesn't define arguments on any of the nodes it creates, unfortunately. Instead you would need to create these yourself. The easiest way to do that is through the createResolvers API.
Here's a similar example from a project of mine:
// in gatsby-node.js
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
SourceArticleCollection: {
// Add articles from the selected section(s)
articles: {
type: ["SourceArticle"],
args: {
// here's where the `limit` argument is added
limit: {
type: "Int",
},
},
resolve: async (source, args, context, info) => {
// this function just needs to return the data for the field;
// in this case, I'm able to fetch a list of the top-level
// entries that match a particular condition, but in your case
// you might want to instead use the existing data in your
// `source` and just slice it in JS.
const articles = await context.nodeModel.runQuery({
query: {
filter: {
category: {
section: {
id: {
in: source.sections.map((s) => s._ref),
},
},
},
},
},
type: "SourceArticle",
})
return (articles || []).slice(0, args.limit || source.limit || 20)
},
},
},
})
}
Because resolvers run as part of the data-fetching routines that support the GraphQL API, this will run server-side at build-time and only the truncated/prepared data will be sent down to the client at request time.
The title may be miss leading but I'm not really sure how do I ask this question correctly. Here is the problem: I'd like to query my own API(not created yet so I made placeholder data) for global settings which might change in the future and I will only need to rebuild the website instead of editing it manually, I want to create source node called CmsSettings and pass it to GraphQL (structure similar to site.siteMetadata) but I don't know how can I achieve that. What I achieved so far is to create a source node called allCmsSettings which has my data as an object in nodes array.
exports.sourceNodes = ({ actions, createNodeId, createContentDigest }) => {
const { createNode } = actions;
const myData = {
key: 123,
app_title: `The foo field of my node`,
...
}
const nodeContent = JSON.stringify(myData);
const nodeMeta = {
id: createNodeId(`my-data${ myData.key }`),
parent: null,
children: [],
internal: {
type: `CmsSettings`,
mediaType: `text/html`,
content: nodeContent,
contentDigest: createContentDigest(myData)
}
}
const node = Object.assign({}, myData, nodeMeta);
createNode(node);
}
Here is the query used to get the data of the source node
allCmsSettings {
edges {
node {
id
app_title
...
}
}
}
Creating a query results in an array of results(which I know is the result of creating source nodes) but I'd like to create that source so that I could query it like this and:
CmsSettings {
app_title
app_keywords
app_descriptions
app_logo_path
brand_name
...
}
You get the point. I was browsing the gatsby node API but I can't find how to achieve this.
Thank you for your help
Nevermind, the answer is pretty simple, if you are new to gatsby just like me the sourceNodes export creates 2 graphql fields for you with all prefix and camel case source node. The thing that I wanted to make is already there and is queryable with
cmsSettings {
app_title
app_keywords
app_descriptions
app_logo_path
brand_name
...
}
Notice the lowercase letter even though it was declared as CmsSettings. It seems that gatsby really does some magic under the hood.
I am a beginner in Backend developing, and I have this array called (Movie). I use expressJS and I want to save the array on MongoDB.I will use Mongodb atlas for my database. I appreciate your help
I tried to follow this instruction on this website:
https://medium.com/#lavitr01051977/node-express-js-aea19636a500
I ignored the first steps and starts from ( Connecting to the Database ) title but It doesn't work.
var express = require('express')
var app = express()
app.get('/', (req, res) => {
res.send('ok')
});
//movie array
const movies = [
{ title: 'Jaws', year: 1975, rating: 8 },
{ title: 'Avatar', year: 2009, rating: 7.8 },
{ title: 'Brazil', year: 1985, rating: 8 },
{ title: 'الإرهاب والكباب', year: 1992, rating: 6.2 }
]
//read the array movie
app.get('/movies/read/',(req,res) => {
res.send({status:200, data:movies})
})
//add elements to array movies
app.get('/movies/add',(req,res) => {
var t = req.query.title
var y = req.query.year
var r = req.query.rating
if(t == undefined || y == undefined || y.length > 4 || isNaN(y)) {
res.send({status:403, error:true, message:'you cannot create a movie without providing a title and a year'})
}
if (r == "") {
r = 4
}
movies.push({title: t, year: y, rating: r})
res.send({status:200, data:movies})
})
//delete elements from array movies
app.get('/movies/delete/:ID',(req,res) => {
var d = req.params.ID
if (d > 0 && d < movies.length ) {
movies.splice(d-1, 1)
res.send({status:200, message: movies})
}
else {
res.send({status:404, error:true, message:'the movie <ID> does not exist'})
}
})
//update elements from array movies
app.get('/movies/update/:ID',(req,res) => {
let c = req.params.ID
let x = req.query.title
let y = req.query.year
let z = req.query.rating
function update(a, b) {
if(a != undefined || a == "") {
movies[c-1][b] = a
}
}
if(c > 0 && c < movies.length ) {
update(x, 'title')
update(y, 'year')
update(z, 'rating')
res.send({status:200, message: movies})
}
else {
res.send({status:404, error:true, message:'the movie <ID> does not exist'})
}
})
app.listen(3000, () => console.log('listinig on port 3000'))
I expect the answer is like the link that I put it above on medium.com website
mongoose is a framework that facilitates interacting with MongoDB. Actually you basically never want to do all the validation, casting, and logic boilerplate on your own, so why reinvent the wheel.
And since you're a beginner, don't be afraid of frameworks. There are many useful frameworks for many areas of backend and frontend to make life easier for you.
The article you shared is self-explanatory, but I will sum up only the database part for you (I won't go deep into your code, no donkey work. the rest is up to you):
1) First of all install mongoose.
npm install mongoose
The article has --save which is no need to add anymore, as "npm install saves any specified packages into dependencies by default."(ref.)
2) to able to access and use mongoose, you need to import it, in node way, that is require().
const express = require(‘express’)
const mongoose = require(“mongoose”);
const bodyParser = require(‘body-parser’);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
And what's body-parser there for?
When dealing with database in express, you'll sooner or later come across errors like this one.
and the reason why we need one after all is best explained in this answer.
Also, recent versions of express has its own body parser now, so you can use app.use(express.json()) instead of app.use(bodyParser.json()).
Important: body-parser must be before your routes.
3) use mongoose.connect(url).
url argument is what you find in your MongoDB Atlas. :
Location: clusters tab -> connect -> connect your application -> driver node.js
Which gives you, something like this:
mongodb+srv://<user>:<password>#,cluster>.mongodb.net/test?retryWrites=true&w=majority
Important: you use user and password of the user you made within Database Access tab, not your own user and password.
You can set up your environment variables to secure sensitive and changeable data. But I prefer using config.js for simplicity, and which usually resides in the root of app.
Not only you can secure them (like for using .gitignore), but also easily modify them as there are variables that might change from one environment to another environment, making them available in one place and easy to find, instead of looking for them to change all over your app.
For .env file approach, read this article.
Important: in case you want to put your code in github or anywhere online, which one reason we use config.js, don't forget to add this file in .gitignore to avoid such sensitive data get leaked and exposed to others online.
in config.js you can do so:
exports.username = 'your user';
exports.pass = 'your pass';
exports.myCluster = 'your cluster's name';
Then import them so:
const { username, pass, myCluster } = require('./config'); <- the path might be different for you!
Tip: You can use back-tick (` `) to easily insert those variables for const url, through interpolation.
That is:
const url = `mongodb+srv://${username}:${password},${myCluster}.mongodb.net/test?retryWrites=true&w=majority`
Important: make sure to whitelist your IP from MongoDB side (atlas), otherwise you will get connection error.
Under security: Network Access -> IP Whitelist
You could use 0.0.0.0/0 to whitelist all IPs.
Also, when using VPN, your IP will change too.
4) last but not least, after connecting to database, you need to define your schema:
const moviesSchema = new mongoose.Schema({
title: String,
year: Number,
rating: Number
});
And
const Movies = mongoose.model(“Movies”, moviesSchema);
Tip: A common mistake many newbies make is that they forgot to use new:
new mongoose.Schema({...})
If you want to create your model in a separate file (which is the best practice), you will need to modify your const Movies so:
module.exports = mongoose.model(“Movies”, moviesSchema);
Don't forgot to add const mongoose = require('mongoose'); in that separate js model file.
And in wherever you use want to use this model, you import so:
const Movies= require('../models/movies'); (the path may different for your app)
The rest, my friend, is up to you. What you want to do with your database and how to use it.
Note to others: I put so much time and mind to this as I was writing this. Please, if you see something wrong, or think you can add something, feel free to edit and improve my answer.
I would suggest you to take look at mongoose framework to interact with a Mongo database using NodeJS.
However, in the code you've provided you're not interacting with any database. You would need to define a Schema and then you could save a new doc or do any other action with your collection. Please follow some 'Get started' guide on how to do it.
Hope it helps!
I ll explain step by step. NOTE THAT THIS PROCESS SHOULD BE RUN ONLY ONCE. SO YOU SHOULD ADD THIS CODE TO A SEPARATE MODULE AND RUN IT ONCE. otherwise you will keep adding more items to the db. lets name this module
movies.js
//you need to connect to mongodb through mongoose.
const mongoose = require("mongoose");
mongoose
.connect("mongodb://127.0.0.1:27017/movies", { //will create movies db automatically
useNewUrlParser: true,
useCreateIndex: true
})
.catch(err => {
console.log(err.message);
process.exit(1);
})
.then(() => {
console.log("connected");
});
//next create a schema and model:
const movieSchema = new mongoose.Schema({
title: String,
year: Number,
rating: Number
});
const Movie = mongoose.model("Movie", movieSchema);
//create movies array based on `Movie model` so u can use save() method.
const movies = [
new Movie({ title: "Jaws", year: 1975, rating: 8 }),
new Movie({ title: "Avatar", year: 2009, rating: 7.8 }),
new Movie({ title: "Brazil", year: 1985, rating: 8 }),
new Movie({ title: "الإرهاب والكباب", year: 1992, rating: 6.2 })
];
//Last step save it.
movies.map(async (p, index) => {
await p.save((err, result) => {
if (index === movies.length - 1) {
console.log("DONE!");
mongoose.disconnect();
}
});
});
map is an array method.it iterates over array and save each item inside the array. Once every item in the array is saved we need to disconnect from db. array method takes 2 arguments. on is each item inside the array, second one is the index of each item. index in array starts from 0, so last item's index in movies array is 3 but length of the array is 4 so once 4-1=3 that means we saved every item in the array.
Now run the code
node movies.js
I've been working with Firebase for a little while, and like their suggestion to keep data denormalized. My only problem is figuring out the best way to query across multiple collections. For example, I have an Identity object which holds info on my users:
identities: {
$identity: {
name: string,
studio: $studioID
}}
That corresponds to a Studio object:
studios: {
$studio: {
name: string,
owner: $identityID,
location: $locationID
}}
This object references the owner, and also their location. The location object references Classes, which references Students.... on and on. Right now, in order to fetch a referenced object, I'm doing something like this:
Auth.loginUser(email, password, (success) => {
const identityRef = firebase.database().ref('/identity');
identityRef.child(success.uid).on("value", function(identitySnapshot) {
const identity = identitySnapshot.val();
const studioRef = firebase.database().ref('/studios');
dispatch({type: 'UPDATE_IDENTITY', identity})
studioRef.child(identity.studioID).on("value", function(studioSnapshot) {
const studio = studioSnapshot.val();
dispatch({type: 'UPDATE_STUDIO', studio});
})}); });
I would continue nesting my calls for Location, Classes, Students, etc. Is there a better way to do this?
Consider the following structures:
identities: {
$identityKey: {
name: string
}
}
identities_studios: {
$identityKey: {
$studioKey: {
name: string
}
}
}
identities_studios_locations: {
$identityKey: {
$studioKey: {
$locationKey: {
lat: string,
lng: string
}
}
}
}
The first, identities, only stores info about the identities as usual.
The second, identities_studios, only stores info about the studios, but the studios are grouped by $identityKey.
The third, identities_studios_locations, only stores info about the locations, but they are grouped firstly by $studioKey and secondly by $identityKey.
Now you can do this:
const db = firebase.database()
Auth.loginUser(email, password, success => {
db.ref(`/identities/${success.uid}`).on("value", snap => { ... }
db.ref(`/identities_studios/${success.uid}`).on("value", snap => { ... }
db.ref(`/identities_studios_locations/${success.uid}`).on("value", snap => { ... }
}
Instead of making multiple requests one after the other, we get them to run simultaneously.
If you want, after getting all this info from the database, you can transform the data structure to whatever you want: one array for identities, another for studios, another for locations, etc.; or a single array of identities with nested studios which in turn have nested locations etc.