post
기능까지 구현을 마치고 읽어오는 get
단계입니다. post
로 등록된 document에는 imagePath란 필드에 files collection의 filename과 같은 값을 갖고 있습니다. 이점을 이용해서 article에는 binary로 된 이미지 파일이 존재하지 않기 때문에, imagePath란 필드를 사용해서 files 그리고 chunks에서 데이터를 가져오는 단계를 거쳐야합니다.
imagePath
의 값을 가져와 files collection에서 검색binary/buffer
를 반환될 객체에 추가이렇게 3단계를 거쳐서 response값을 전달해주려 합니다.
저장되어있는 모든 document를 읽어오는 기능으로 readAll()
을 구현하였습니다.
// read all
readAll = async () => {
try {
// db query
const res = await Article.find();
var updatedRes = []
// get Image
async function updateImageProperty(res, updatedRes) {
// iterable
for (const document of res) {
const { imagePath } = document;
if (imagePath != null) {
const searchImageFile = await ArticleImage.findOne({ filename: imagePath });
if (searchImageFile != null) {
// get chunks
const searchImageChunk = await ArticleImageChunk.find({ files_id: searchImageFile._id });
var buffer = '';
searchImageChunk.map((doc) => buffer += Buffer.from(doc.data, 'binary').toString('base64'));
// put 'image' key and value
document['image'] = buffer;
updatedRes.push(document);
// console.log(JSON.stringify(updatedRes));
}
} else {
updatedRes.push(document);
}
}
return updatedRes;
}
const response = await updateImageProperty(res, updatedRes);
if (!response) return onGetNotFound;
return onGetSuccess(updatedRes);
} catch (error) {
console.error(error);
return onGetFailure(err);
}
}
res
에 저장합니다. updatedRes
는 client에게 보낼 return(최종 response)
값입니다.async (비동기)
작업을 할 때, forEach
를 사용하지 않고 for .. of
for loop 를 사용합니다.forEach
는 반복문을 돌면서 function
내의 내용만을 처리하기 때문에, 병렬로 순차 실행하는 것은 for loop
를 이용해야합니다. forEach
는 반복문이 종료되기까지 기다려주지 않습니다. imagePath
값과 같은 값을 검색합니다. files_id
와 files의 ObjectId
값이 같은 값을 검색합니다.n:0
, n:1
이런식으로 분리가 되어있기 때문에 map
함수를 통해서 buffer
에 더해주었습니다. 그리고 더해준 buffer
를 document 내 image
필드 값으로 overwrite
해줍니다.response
로 전달해줍니다.서버에서 전달되는 값을 저는 아래와 같이 설정해두었습니다.
var onGetSuccess = (body) => {
return {
status: 200,
result: {
message: "[GET] msg received",
result: body
}
};
}
따라서 client로 전달되는 값은 result
로 조회가 가능합니다. result
내에는 List 타입으로 반환되어 전달되기 때문에 적절한 parsing 작업을 아래와 같이 해주었습니다.
// GET - ALL
Future<List<Article>> findAll() async {
final res = await http.get(baseURL);
if (res.statusCode == 200) {
print('status 200');
final parsedJson = json.decode(res.body)['result'] as List;
final list = parsedJson.map((json) => Article.fromJson(json)).toList();
return list;
} else {
throw Exception(res.body.toString());
}
}
추가로 이미지를 처리할때는 Image.memory(Uri.parse(base64).data.contentAsBytes())
처럼 구현하였습니다. 해당코드는 아래 코드와 같습니다.
class ImageWrapper extends StatefulWidget {
final String image;
ImageWrapper({this.image});
_ImageWrapperState createState() => _ImageWrapperState();
}
class _ImageWrapperState extends State<ImageWrapper> {
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Container(
child: Align(
alignment: Alignment.center,
widthFactor: 0.8,
heightFactor: 0.8,
child: Image.memory(
base64Decode(widget.image),
width: size.width * 0.27,
height: size.width * 0.27,
alignment: Alignment.center,
errorBuilder: (context, error, stackTrace) => Icon(
Icons.error_outline_rounded,
size: 24,
color: themeGrayText),
fit: BoxFit.cover,
),
),
),
);
}
}
위에 화면처럼 왼쪽에는 이미지 파일에 대한 buffer를 출력해보고 오른쪽에는 에뮬레이터를 통해서 값을 출력해보았습니다.