묻고 답해요
169만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
N:M tag 부분 구현 중 findOne 조회 부분 에러
products.service.ts에서 create 부근에 tag를 저장 하기 전 tag를 미리 조회하는 부분을 구현 중인데 findOne에서 {name: tagname} 을 구현하려고 할 때 다음과 같은 에러가 발생합니다. save에서는 에러가 발생하지 않는데 findOne 조회 부분만 에러가 발생하네요관련된 코드 같이 보내드립니다.createProduct.input.tsimport { InputType, Field, Int } from '@nestjs/graphql'; import { Min } from 'class-validator'; import { ProductSaleslocationInput } from 'src/apis/productsSaleslocation/entities/dto/productSaleslocation.input'; @InputType() export class CreateProductInput { @Field(() => String) name: string; @Field(() => String) description: string; @Min(0) @Field(() => Int) price: number; @Field(() => ProductSaleslocationInput) productSaleslocation: ProductSaleslocationInput; @Field(() => String) productCategotyId: string; @Field(() => [String]) productTags: string[]; } products.entity.tsimport { Field, Int, ObjectType } from '@nestjs/graphql'; import { ProductCategory } from 'src/apis/productsCategory/entities/productsCategory.entity'; import { ProductTag } from 'src/apis/productsTags/productTags.entity'; import { User } from 'src/apis/users/users.entity'; import { Column, DeleteDateColumn, Entity, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToOne, PrimaryGeneratedColumn, } from 'typeorm'; import { ProductSaleslocation } from '../../productsSaleslocation/entities/productsSaleslocation.entity'; @Entity() @ObjectType() export class Product { @PrimaryGeneratedColumn('uuid') @Field(() => String) id: string; @Field(() => String) @Column() name: string; @Field(() => String) @Column() description: string; @Field(() => Int) @Column() price: number; @Field(() => Boolean) @Column({ default: false }) isSoldout: boolean; @DeleteDateColumn() deletedAt: Date; @Field(() => ProductSaleslocation) @JoinColumn() @OneToOne(() => ProductSaleslocation) productSaleslocation: ProductSaleslocation; @Field(() => ProductCategory) @ManyToOne(() => ProductCategory) productCategory: ProductCategory; @Field(() => User) @ManyToOne(() => User) user: User; @JoinTable() @ManyToMany(() => ProductTag, (productTags) => productTags.products) @Field(() => [ProductTag]) productTags: ProductTag[]; } productTags.entity.tsimport { Field, ObjectType } from '@nestjs/graphql'; import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm'; import { Product } from '../products/entities/products.entity'; @Entity() @ObjectType() export class ProductTag { @Field(() => String) @PrimaryGeneratedColumn('uuid') id: string; @Column() @Field(() => String) name: string; @Field(() => [Product]) @ManyToMany(() => Product, (products) => products.productTags) products: Product[]; } products.service.tsimport { Product } from './entities/products.entity'; import { Injectable, UnprocessableEntityException } from '@nestjs/common'; import { Repository } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; import { ProductSaleslocation } from '../productsSaleslocation/entities/productsSaleslocation.entity'; import { ProductTag } from '../productsTags/productTags.entity'; @Injectable() export class ProductService { constructor( @InjectRepository(Product) private readonly productRepository: Repository<Product>, @InjectRepository(ProductSaleslocation) private readonly productSaleslocationRepository: Repository<ProductSaleslocation>, @InjectRepository(ProductTag) private readonly productTagRepository: Repository<ProductTag>, ) {} async findAll() { return await this.productRepository.find({ relations: ['productSaleslocation', 'productCategory', 'productTags'], }); } async findOne({ productId }) { return await this.productRepository.findOne({ where: { id: productId }, relations: ['productSaleslocation', 'productCategory', 'productTags'], }); } async create({ createProductInput }) { // 1. 상품만 등록하는 경우 // const result = await this.productRepository.save({ // ...createProductInput, // // 하나 하나 직접 나열하는 방식 // // name: createProductInput.name, // // description: createProductInput.description, // // price: createProductInput.price, // }); // 2. 상품과 상품거래 위치 같이 등록 const { productSaleslocation, productCategotyId, productTag, ...product } = createProductInput; const result = await this.productSaleslocationRepository.save({ ...productSaleslocation, }); // productTag // ["#electronics, #computer"] const result2 = []; // [{name: ..., id: ...}] for (let i = 0; i < productTags.length; i++) { const tagName = productTags[i].replace('#', ''); // check the tags that has already registered const checkTag = await this.productTagRepository.findOne({ name: tagName, }); // if the tags has been existed if (checkTag) { result2.push(checkTag); // if the tags hasn't been existed } else { const newTag = await this.productTagRepository.save({ name: tagName }); result2.push(newTag); } } const result3 = await this.productRepository.save({ ...product, productSaleslocation: result, // result 통째로 넣기 vs id만 넣기 productCategory: { id: productCategotyId }, productTags: result2, }); return result3; } async update({ productId, updateProductInput }) { const myProduct = await this.productRepository.findOne({ where: { id: productId }, }); const newProduct = { ...myProduct, id: productId, ...updateProductInput, }; return await this.productRepository.save(newProduct); } async checkSoldOut({ productId }) { const product = await this.productRepository.findOne({ where: { id: productId }, }); if (product.isSoldout) { throw new UnprocessableEntityException('Sold out'); } // if(product.isSoldout) { // throw new HttpException('이미 판매 완료 된 상품입니다.', HttpStatus.UNPROCESSABLE_ENTITY) // } } async delete({ productId }) { // 1. 실제 삭제 // const result = await this.productRepository.delete({ id: productId }); // return result.affected ? true : false // 2. 소프트 삭제(직접 구현) - isDeleted // this.productRepository.update({ id: productId }, { isDeleted: true }); // 3. 소프트 삭제(직접 구현) - deletedAt // this.productRepository.update({ id: productId }, { deletedAt: new Date() }); // 4. 소프트 삭제(TypeORM 제공) - softRemove - id로만 삭제 가능 // this.productRepository.softRemove({ id: productId }); // 4 . 소프트 삭제(TypeORM 제공) - softDelete const result = await this.productRepository.softDelete({ id: productId }); return result.affected ? true : false; } } 내용 확인 부탁드립니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
안녕하세요 질문있습니다!
@ObjectType이랑 @EntryType이랑 같이 사용을 할수는 없는건가요??dto와 entry가 다른부분이 없어서 같이 쓰는게 낫겠다싶어서 시도하려니 안되네요확실히 역할을 나눠야하는건가요??
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
폴더 속 폴더에 있는 소스 배포
강사님 제가 넷플릭스 소스를 [git아이디/Repositories폴더/하위a폴더/하위b폴더]b폴더에 저장을 했다면homepage경로와 base경로를 어떻게 설정해야하나요?혹시 배포를 할땐 Repositories 폴더에 있는 소스들만 배포가 가능한건가요?
-
미해결실전! 스프링부트 상품-주문 API 개발로 알아보는 TDD
코드 스타일에 대해서 질문드립니다.
변수들에 final 키워드를 붙이시는 이유class를 만들때 접근지정자 public 을 지우시는 이유메서드를 static 으로 생성하는 이유위의 점들이 궁금합니다.
-
미해결테스트주도개발(TDD)로 만드는 NodeJS API 서버
슈퍼 테스트2 강의 질문입니다
describe('GET /users는', () => { it('user리스트를 limit만큼 가져왔다', (done) => { request(app) .get('/users') .end((err, res) => { console.log(res.body) done() // 우리가 만든 API서버는 비동기로 동작한다. 그래서 비동기에 대한 처리로 콜백함수를 호출해야 한다?? }) }) }) 강사님께서 콜백함수 done()을 호출하는 부분에서 다음과 같이 말하셨습니다..."우리가 만든 API서버는 비동기로 동작한다. 그래서 비동기에 대한 처리를 해야한다"그런데 done()이라는 콜백함수를 호출하는 것이 어떤의미에서 비동기에 대한 처린인지 이해가 가지않아 질문을 남깁니다.
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
선생님 Props내려줄때
data 프롭의 경우는 이미 id ,title, completed 같은 정보들이 다 들어있는거니까 data프롭만 내려받아서 List.js에서 .id, .title, .completed로 써도 문제가 없는거죠?
-
미해결테스트주도개발(TDD)로 만드는 NodeJS API 서버
응답 강의중 질문입니다
Pdf 파일에 "204:내용없음, DELETE"라고 되어 있어 질문이 생겼습니다.204는 삭제요청을 했는데 내용 없을때 리턴해주는 상태 코드인건가요?? Get요청을 했는데 없을시에도 204를 리턴해 주어도 될까요?3xx 잘가~ 는 어떤 의미로 받아들여야 할지...이해가 가지 않습니다...
-
미해결테스트주도개발(TDD)로 만드는 NodeJS API 서버
요청 형식 강의 질문입니다
HTTP경로로 자원을 식별한다고 알려주셨는데! lecture?user={id} 와 같은 식으로는 사용하지 않는건가요?
-
미해결테스트주도개발(TDD)로 만드는 NodeJS API 서버
비동기 세계1 강의 내용 질문입니다
노드는 기본적으로 비동기로 동작한다라는 텍스트가 있는데! console.log()를 출력해보면 동기로 동작하는걸 볼 수 있습니다....기본적으로 위에서 아래로 동기로 동작하는데 비동기로 동작하는 함수가 많다는 의미의 텍스트 일까요?
-
해결됨따라하며 배우는 리액트 A-Z[19버전 반영]
handleSubmit을 useCallback으로
handleSubmit를 useCallback으로 감싸서 만들어봤는데const handleSubmit = useCallback( (e) => { e.preventDefault(); let newTodoData = todoData.map((data) => { if (data.id === id) { data.title = editedTitle; } return data; }); console.log(newTodoData); setTodoData(newTodoData); setIsEditing(false); }, [todoData, setTodoData, id, editedTitle] );의존성배열에 setTodoData 를 넣지않으면 아래오류가 나면서 handleSubmit 함수가 실행되지 않더라구요React Hook useCallback has a missing dependency: 'setTodoData'. Either include it or remove the dependency array. If 'setTodoData' changes too often, find the parent component that defines it and wrap that definition in useCallback제 지식으론 의존성배열에 todoData만 넣으면 될줄 알았는데 왜 setTodoData 까지 같이 넣어야하는지 궁금합니다!
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
axios.js 에 인스턴스를 만든 후 Banner.js 에 import 할 때 문의
안녕하세요!axios.js 에 인스턴스를 만들고 그 인스턴스를 export default instance; 로 export 해줬는데그렇다면 Banner.js 에서 가져와서 사용할 때import instance from "../api/axios"; 라고 가져와서 instance.get(requests.fetchNowPlaying);이런 식으로 사용하는게 맞지 않나 생각이 들어서 질문 드립니다.
-
해결됨따라하며 배우는 리액트 A-Z[19버전 반영]
Lists.js에서 List컴포넌트로 프롭스 보내줄때,
<List key={data.id} id={data.id} title={data.title} completed={data.completed} todoData={todoData} setTodoData={setTodoData} provided={provided} snapshot={snapshot} />List에 프롭스 key를 넘겨주었는데왜 List.js에서는 key를 받지 않은 건가요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
나만의미니프로젝트 cheerio관련질문
원하는 키워드의 값을 담은 상수를 console.log(key,value) 하면 줄바꿈되면서 안에 있는 전체 값들이 나오더라구요 ( const key = $(el).attr("property").split(":")[1]; const value = $(el).attr("content"); 부분입니다)근데 이 값들을 db에 저장하려 for문을 이용해 배열에 넣어봤더니 console.log(key,value)해서 나온 값들이 아닌 마지막 값만 들어갑니다 key와 value에 어떤 형태로 값이 스크랩핑되어 들어가있는건가요..?상수에 배열형태로 들어간 것도 아니고 한줄로 값이 들어간 것도 아니고 .. console.log하면 전체가 나오기는 하나줄바꿈이 되어 나와서 갈피를 못잡겠습니다..스크래핑한 값을 어떻게 저장을하고 넘겨야할지 db로 넘겨야할지 전혀 모르겠습니다................................. 이틀동안 찾아봐도 해결이 안되어서 질문 남깁니다..
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
오류 질문
검색을 해보니 컴포넌트 명 관련해서 에러 라고 나와져있는데 소스 를 확인해봐도 오타 문제는 아닌거같아 강사님께 여쭤봅니다 ㅠㅜ 무슨문제일까요 ?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
배포 강의를 시작하시는 분들은 인스턴스 환경변수 분리까지 보신 후에 하시면 좋을 것 같습니다.
처음에 .env파일을 깃허브에 올리시길래 띠용했지만 곧바로 수정하시는군요.지금은 연습 중이라서 올라가도 크게 문제가 없을 것 같고, 또한, 강사님께서 .env가 깃허브에 올라갔을 때 어떻게 대처하는지 알려주시기 때문에 연습 용도로도 좋아보입니다..env파일을 올리는게 찜찜하신 분들은 인스턴스 환경변수 분리까지 보신 뒤에 하시는게 좋을 것 같고, 나는 .env가 노출 된 상황을 한 번 연습해보고 싶다. 하시는 분들은 차례대로 진행하는 것도 좋을 것 같습니다!
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
userRepositorySpySave 왜 ? 0 이 안나와? 는 보십시오.
```typescriptasync create({ email, password, mobileNumber }) { const user = await this.userRepository.findOne({ where: { email } }); if (user) throw new ConflictException('이미 등록된 이메일 입니다.'); return await this.userRepository.save({ email, password, mobileNumber }); }일때 findOne({ where: { email } }) { const users = this.mydb.filter((el) => el.email === email); if (users.length) return { ...users[0] }; return null; }입니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
1:1 관계 등록 API 강의 creatProduct 시 에러가 발생합니다
삽입시 address 값을 입력했는데도 default 값이 설정되어있지 않다고 에러가 뜹니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
nest 실행 (npm run start:dev)이 너무 오래 걸려요
typescript 기초 강의에서 nest를 처음 실행했는데 실행 시 너무 오래 걸립니다..(약 20~30분 정도) windows os에서 실행 햇는데 이유가 있을까요?현재 컴퓨터 사양은 Memory 32G 에 RAM 16 Core 입니다.매번 이렇게 시간이 걸리면 현실적으로 test가 불가능해서 방법을 구하고자 합니다. +추가yarn으로 실행해봐도 비슷하네요..Windows OS에서 WSL 통해서 Ubuntu 환경에서 실행하고 있습니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
API-Gateway2 섹션 Apollo 서버 구동 에러
Auth와 Resource App 시작 시 아래 사진과 같은 에러가 발생합니다. 강의와 노션에 있는 코드를 그대로 작성했다고 생각하여 패키지 버전 문제로 추정됩니다.현재 제가 사용중인 패키지입니다.강의 중 사용중인 패키지 버전을 공유받고 싶습니다. 해당 오류에 대한 구글링에 실패해서 추가적으로 혹시 알고계신 레퍼런스 있으시면 알려주시면 감사드리겠습니다.
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
params: { append_to_response: "videos" },
const { data: movieDetail } = await axios.get(`movie/${movieId}`, { params: { append_to_response: "videos" }, }); setMovie(movieDetail);안녕하세요 <이미지 배너 생성하기>를 듣다가 이 부분 코드가 이해가 안가서 질문 드립니다.다른 답변적으신거에 append_to_response가 theMovieDB API 서버에서 정해놓은 것이라고 작성하신 것을 봤는데, 어디에 가야 그 내용을 확인할 수 있는지 궁금합니다. 제가 movieDetail을 콘솔로그로 확인해보았을땐 해당 내용이 뜨지않아서요...항상 도움이 되는 강의 잘 수강하고 있습니다!!