mongodbの定理
ドキュメントベース
分散型データベース
mongodbとして保存されているデータはjson-like-document(sqlなど)です.
文書内にCRUDを作成できます.
モンゴルで使用
mongo
私が持っているdbビュー
show dbs
現在使用中のdbを確認
db
使用するdb を選択
use dbName
(現在のレッスンは
dbコレクションビュー
show collections
dbコレクションでのドキュメントの表示
db.collectionName.find()
dbコレクションからすべてのドキュメントを削除
db.collectionName.remove({})
mongoose
createに適用されますが、updateは適用されません.
これは、更新のためのミドルウェアが必要であることを意味する.
findByIdAndUpdate用のpreミドルウェアはありません.
findByIdUpdate findOneAndUpdateを呼び出します.
findOneAndUpdateはsave hookを呼び出しません.また、更新するドキュメントにアクセスできません.
静的保存と更新
Model.findOneAndRemove()
この2つには本当に違いがあります.合理的な理由がない限り、deleteの使用が要求されることが多いです.
https://www.zerocho.com/category/MongoDB/post/579ecb1fc097d015000404dd
ここで記事を読みましたが、モンゴドdbはロールバックできないことに気づきました.removeでは戻れないので、removeではなくdeleteを使うことをお勧めします.
mongoseには良いクエリーエンジンがあります.
dbにパスワードを保存しないでください.
暗号化は重要です
ハッシュは、一方向関数と文字列として表されます.絶対に取り返しがつかない.
同じ入力値は常に同じ出力値です.ただし、出力値は入力値を特定できません.
dbにハッシュパスワードが保存されます.
https://docs.mongodb.com/manual/reference/operator/query/or/#mongodb-query-op.-or
400: bad request
クライアントエラーでリクエストを処理できない場合に使用できます.
404: Not Found
サーバがリクエストされたページが見つからない場合に発生します.サーバに存在しないページにリクエストがある場合、サーバはこのコードを提供します.
通常、ブラウザをリクエストしてレンダリングすると、バックエンドと接続が切断されます(接続を続行するwifiとは異なります).
つまり、誰が送ってきたのか覚えていません.この状態を無状態と呼ぶ.
だからexpress-sessionをインストールします
npm i express-session
server.jsで作成
これにより、サーバはブラウザを単独で覚えることができます.
バックエンドはクッキーを受信しています.
クッキーはバックエンドがブラウザに提供する情報です.
クッキーには一定のルールがあるため、ブラウザはバックエンドにリクエストを発行するたびに、そのリクエストにクッキーを追加します.
セッションidをユーザーにスケールします.
セッションIDを入れた場所はクッキーです.
セッションidはクッキーに格納されますが、データ自体はサーバに格納されます.
ユーザーをログインさせるのはreqです.セッションオブジェクトに情報を入れる
dbを更新する場合、セッションも個別に更新する必要があります.
pugテンプレートはローカルユーザーにアクセスできます.
pugとexpressは、ローカルユーザーを共有できるように設定されています.
変数をlocalsオブジェクトとしてテンプレートにグローバルに送信できます.
localsオブジェクトはすべてのpugテンプレートにインポートされました.
サーバーが再起動すると、MongoStoreがインストールされるまですべてのセッションが消えます.
npm i connect-mongo
セッションはデバッガとしてRAMメモリに格納され、RAMメモリは消費時に消失するため、mongoStoreとして指定すると、セッションはmongodbに保存されます.すなわち、消費時に消えるまでセカンダリメモリに格納されます.
saveUninitialized : true
値が設定されていない転送日セッションをリポジトリに保存し、返信などのセッション所有者にクッキーを渡します.
saveUninitialized : false
req.セッション内の値を変更した瞬間、セッションをStoreに保存してクッキーを渡します.
resave: true
セッションが変更されていない場合でも、セッションを保存します.
resave: false
保存するにはセッションを変更する必要があります
関連項目:https://github.com/expressjs/session#resave
セッションを破棄します.
デフォルトではfindByIdAndUpdateは更新前のドキュメントを返し、オプション{new:true}を作成すると更新後のデータが返されます.
分散型データベース
mongodbとして保存されているデータはjson-like-document(sqlなど)です.
文書内にCRUDを作成できます.
ターミナルの操作
モンゴルで使用
mongo
私が持っているdbビュー
show dbs
現在使用中のdbを確認
db
使用するdb を選択
use dbName
(現在のレッスンは
use wetube
)dbコレクションビュー
show collections
dbコレクションでのドキュメントの表示
db.collectionName.find()
dbコレクションからすべてのドキュメントを削除
db.collectionName.remove({})
mongoose
node.jsとmongodbのパッケージを接続します.import mongoose from 'mongoose';
mongoose.connect('mongodb://127.0.0.1:27017/vsa', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = mongoose.connection;
const handleOpen = () => console.log('✅ Connected to DB');
const handleError = (error) => console.log('❌ DB Error', error);
// on은 여러번, once는 한번만 실행.
db.on('error', handleError);
db.once('open', handleOpen);
import './db';
model
モデルはMongooseがMongodbデータがどのようなものかを教えてくれます
そう言えばmongoseはデータの作成、削除、修正、検索に役立ちます.
データモデルでは、ファイルの最初のアルファベットは大文字です.
schemaはデータの形式です.
無効なデータをドキュメントに書き込めません.import mongoose from 'mongoose';
const videoSchema = new mongoose.Schema({
title: { type: String, required: true, trim: true, maxLength: 80 },
description: { type: String, required: true, trim: true, minLength: 20 },
createdAt: { type: Date, required: true, default: Date.now },
hashtags: [{ type: String, trim: true }],
meta: {
views: { type: Number, default: 0, required: true },
rating: { type: Number, default: 0, required: true },
},
});
// model의 이름, 데이터 형태 작성.
const Video = mongoose.model('Video', videoSchema);
export default Video;
init.jsimport './db';
import './models/Video';
query
import Video from '../models/Video';
export const home = (req, res) => {
Video.find({}, (error, videos) => {
console.log('Finished');
return res.render('home', { pageTitle: 'Home', videos });
});
};
async await
import Video from '../models/Video';
export const home = async (req, res) => {
const videos = await Video.find({});
return res.render('home', { pageTitle: 'Home', videos });
};
dbに保存する方法。
import mongoose from 'mongoose';
mongoose.connect('mongodb://127.0.0.1:27017/vsa', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = mongoose.connection;
const handleOpen = () => console.log('✅ Connected to DB');
const handleError = (error) => console.log('❌ DB Error', error);
// on은 여러번, once는 한번만 실행.
db.on('error', handleError);
db.once('open', handleOpen);
import './db';
import mongoose from 'mongoose';
const videoSchema = new mongoose.Schema({
title: { type: String, required: true, trim: true, maxLength: 80 },
description: { type: String, required: true, trim: true, minLength: 20 },
createdAt: { type: Date, required: true, default: Date.now },
hashtags: [{ type: String, trim: true }],
meta: {
views: { type: Number, default: 0, required: true },
rating: { type: Number, default: 0, required: true },
},
});
// model의 이름, 데이터 형태 작성.
const Video = mongoose.model('Video', videoSchema);
export default Video;
import './db';
import './models/Video';
import Video from '../models/Video';
export const home = (req, res) => {
Video.find({}, (error, videos) => {
console.log('Finished');
return res.render('home', { pageTitle: 'Home', videos });
});
};
import Video from '../models/Video';
export const home = async (req, res) => {
const videos = await Video.find({});
return res.render('home', { pageTitle: 'Home', videos });
};
export const postUpload = async (req, res) => {
const { title, description, hashtags } = req.body;
const video = new Video({
title,
description,
createdAt: Date.now(),
hashtags: hashtags.split(',').map((word) => `#${word}`),
meta: {
views: 0,
rating: 0,
},
});
await video.save();
return res.redirect('/');
};
export const postUpload = async (req, res) => {
const { title, description, hashtags } = req.body;
try {
await Video.create({
title,
description,
createdAt: Date.now(),
hashtags: hashtags.split(',').map((word) => `#${word}`),
meta: {
views: 0,
rating: 0,
},
});
} catch (error) {
return res.render('upload', {
pageTitle: 'Upload Video',
errorMessage: error._message,
});
}
return res.redirect('/');
};
オブジェクトを検索します。
export const watch = async (req, res) => {
const { id } = req.params;
const video = await Video.findById(id);
return res.render('watch', { pageTitle: `Watching Home`, video });
};
オブジェクトを検索して更新します。
export const postEdit = async (req, res) => {
const { id } = req.params;
const { title, description, hashtags } = req.body;
const video = await Video.exists({ _id: id });
if (!video) {
return res.render('404', { pageTitle: 'Video not found.' });
}
await Video.findByIdAndUpdate(id, {
title,
description,
hashtags: hashtags
.split(',')
.map((word) => (word.startsWith('#') ? word : `#${word}`)),
});
return res.redirect(`/videos/${id}`);
};
作成前に処理する関数=>Mongooseの前中間パッケージを使用
// this는 새문서(새객체)를 나타냄.
videoSchema.pre('save', async function () {
this.hashtags = this.hashtags[0]
.split(',')
.map((word) => (word.startsWith('#') ? word : `#${word}`));
});
更新中のドキュメント(作成時)にアクセスできます.createに適用されますが、updateは適用されません.
これは、更新のためのミドルウェアが必要であることを意味する.
静的、更新可能な関数
findByIdAndUpdate用のpreミドルウェアはありません.
findByIdUpdate findOneAndUpdateを呼び出します.
findOneAndUpdateはsave hookを呼び出しません.また、更新するドキュメントにアクセスできません.
静的保存と更新
videoSchema.static('formatHashtags', function (hashtags) {
return hashtags
.split(',')
.map((word) => (word.startsWith('#') ? word : `#${word}`));
});
export const postEdit = async (req, res) => {
const { id } = req.params;
const { title, description, hashtags } = req.body;
const video = await Video.exists({ _id: id });
if (!video) {
return res.render('404', { pageTitle: 'Video not found.' });
}
await Video.findByIdAndUpdate(id, {
title,
description,
hashtags: Video.formatHashtags(hashtags),
});
return res.redirect(`/videos/${id}`);
};
オブジェクトの削除
export const deleteVideo = async (req, res) => {
const { id } = req.params;
await Video.findByIdAndDelete(id);
return res.redirect('/');
};
Model.findOneAndDelete()Model.findOneAndRemove()
この2つには本当に違いがあります.合理的な理由がない限り、deleteの使用が要求されることが多いです.
https://www.zerocho.com/category/MongoDB/post/579ecb1fc097d015000404dd
ここで記事を読みましたが、モンゴドdbはロールバックできないことに気づきました.removeでは戻れないので、removeではなくdeleteを使うことをお勧めします.
配置
export const home = async (req, res) => {
const videos = await Video.find({}).sort({ createdAt: 'desc' });
return res.render('home', { pageTitle: 'Home', videos });
};
検索
mongoseには良いクエリーエンジンがあります.
extends base.pug
include mixins/video
block content
form(method="GET")
input(placeholder="Search by title", name="keyword", type="text")
input(type="submit", value="Search now")
div
each video in videos
+video(video)
export const search = (req, res) => {
const { keyword } = req.query;
let videos = [];
if (keyword) {
videos = await Video.find({
title: {
// mongodb 가 하는 거임.
$regex: new RegExp(`${keyword}$`, 'i'),
},
});
}
return res.render('search', { pageTitle: 'Search', videos });
};
関連項目:https://docs.mongodb.com/manual/reference/operator/query/regex/bcrypt
dbにパスワードを保存しないでください.
暗号化は重要です
ハッシュは、一方向関数と文字列として表されます.絶対に取り返しがつかない.
同じ入力値は常に同じ出力値です.ただし、出力値は入力値を特定できません.
dbにハッシュパスワードが保存されます.
userSchema.pre('save', async function () {
// 숫자는 해싱횟수(salt rounds), async await 쓰면 콜백 안써도 됨.
this.password = await bcrypt.hash(this.password, 5);
});
compareexport const postLogin = async (req, res) => {
const { username, password } = req.body;
const pageTitle = 'Login';
const user = await User.findOne({ username });
if (!user) {
return res.status(400).render('login', {
pageTitle,
errorMessage: 'An account with this username does not exists',
});
}
// password를 해싱하고 user.password와 비슷한지 비교(해싱된 횟수는 user.password 앞에 있어서 알 수 있음. 그렇기 때문에 password를 해싱해서 user.password를 비교할 수 있는 거임.)
const ok = await bcrypt.compare(password, user.password);
if (!ok) {
return res.status(400).render('login', {
pageTitle,
errorMessage: 'Wrong password',
});
}
res.redirect('/');
$or
const exists = await User.exists({ $or: [{ username }, { email }] });
if (exists) {
return res.render('join', {
pageTitle,
errorMessage: 'This username/email is already taken.',
});
}
関連項目:[$or]https://docs.mongodb.com/manual/reference/operator/query/or/#mongodb-query-op.-or
status
400: bad request
クライアントエラーでリクエストを処理できない場合に使用できます.
404: Not Found
サーバがリクエストされたページが見つからない場合に発生します.サーバに存在しないページにリクエストがある場合、サーバはこのコードを提供します.
if (password !== password2) {
return res.status(400).render('join', {
pageTitle,
errorMessage: 'Password confirmation does not match',
});
}
session
通常、ブラウザをリクエストしてレンダリングすると、バックエンドと接続が切断されます(接続を続行するwifiとは異なります).
つまり、誰が送ってきたのか覚えていません.この状態を無状態と呼ぶ.
だからexpress-sessionをインストールします
npm i express-session
server.jsで作成
import session from 'express-session';
app.use(
session({
secret: 'Hello!',
resave: true,
saveUninitialized: true,
})
);
セッションというミドルウェアがブラウザにクッキーを送信これにより、サーバはブラウザを単独で覚えることができます.
バックエンドはクッキーを受信しています.
クッキーはバックエンドがブラウザに提供する情報です.
クッキーには一定のルールがあるため、ブラウザはバックエンドにリクエストを発行するたびに、そのリクエストにクッキーを追加します.
セッションidをユーザーにスケールします.
セッションIDを入れた場所はクッキーです.
セッションidはクッキーに格納されますが、データ自体はサーバに格納されます.
ユーザーをログインさせるのはreqです.セッションオブジェクトに情報を入れる
dbを更新する場合、セッションも個別に更新する必要があります.
app.use((req, res, next) => {
// 백엔드가 기억하고 있는 sessions(백엔드가 기억하고 있는 유저들)를 console.log해서 보는거임.
req.sessionStore.all((error, sessions) => {
console.log(sessions);
next();
});
});
pugテンプレートはローカルユーザーにアクセスできます.
pugとexpressは、ローカルユーザーを共有できるように設定されています.
変数をlocalsオブジェクトとしてテンプレートにグローバルに送信できます.
localsオブジェクトはすべてのpugテンプレートにインポートされました.
export const localsMiddleware = (req, res, next) => {
//전역에서 사용 가능한 변수
res.locals.loggedIn = Boolean(req.session.loggedIn);
res.locals.siteName = 'VSA';
res.locals.loggedInUser = req.session.user;
console.log(req.session);
console.log(res.locals);
next();
};
import session from 'express-session';
app.use(localsMiddleware);
更新時に消えるサーバーが再起動すると、MongoStoreがインストールされるまですべてのセッションが消えます.
mongostore
npm i connect-mongo
セッションはデバッガとしてRAMメモリに格納され、RAMメモリは消費時に消失するため、mongoStoreとして指定すると、セッションはmongodbに保存されます.すなわち、消費時に消えるまでセカンダリメモリに格納されます.
import MongoStore from 'connect-mongo';
app.use(
session({
secret: 'Hello!',
resave: true,
saveUninitialized: true,
store: MongoStore.create({ mongoUrl: 'mongodb://127.0.0.1:27017/vsa' }),
})
);
ログインした人にセッションIDを1つだけあげたいなら
saveUninitialized : true
値が設定されていない転送日セッションをリポジトリに保存し、返信などのセッション所有者にクッキーを渡します.
saveUninitialized : false
req.セッション内の値を変更した瞬間、セッションをStoreに保存してクッキーを渡します.
resave: true
セッションが変更されていない場合でも、セッションを保存します.
resave: false
保存するにはセッションを変更する必要があります
関連項目:https://github.com/expressjs/session#resave
import session from 'express-session';
import MongoStore from 'connect-mongo';
app.use(
session({
secret: 'Hello!',
resave: false,
saveUninitialized: false,
store: MongoStore.create({ mongoUrl: 'mongodb://127.0.0.1:27017/vsa' }),
})
);
ログアウトしたい時。
セッションを破棄します.
export const logout = (req, res) => {
req.session.destroy();
return res.redirect('/');
};
findByIdAndUpdate
デフォルトではfindByIdAndUpdateは更新前のドキュメントを返し、オプション{new:true}を作成すると更新後のデータが返されます.
Reference
この問題について(mongodbの定理), 我々は、より多くの情報をここで見つけました https://velog.io/@hrj0903/mongodb-정리テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol