[MONGODB] 몽구스 재귀 채우기
MONGODB몽구스 재귀 채우기
나는 잠시 동안 검색 한 내가 어떤 좋은 답변을 찾지 못했습니다. 제가 DB에 저장하고 있음을 N-깊은 나무를 가지고 있고 전체 트리를 얻을 그래서 결국 나는 모든 부모를 채울 싶습니다
node
-parent
-parent
.
.
-parent
지금까지 나는 레벨 2로 채우는, 그리고 내가 언급 한 바와 같이 나는 레벨 n으로 얻을 필요가있다.
Node.find().populate('parent').exec(function (err, items) {
if (!err) {
Node.populate(items, {path: 'parent.parent'}, function (err, data) {
return res.send(data);
});
} else {
res.statusCode = code;
return res.send(err.message);
}
});
해결법
-
==============================
1.그냥하지 않습니다 :)
그냥하지 않습니다 :)
그렇게 할 좋은 방법은 없습니다. 당신은 몇 가지 할 경우에도 당신이 그것을 가지고거나 이제까지 필요합니다 경우 샤딩과 끔찍한 성능과 문제가있는 것,지도 - 줄일 수 있습니다.
되는 NoSQL 데이터베이스와 몽고 나무 문서를 저장하기위한 정말 좋은 것입니다. 당신은 전체 트리를 저장 한 다음 "찾을 특히 잎"쿼리의 여지가없는 경우 일부 특정 잎을 얻을지도-줄일 수 있습니다. 이 당신을 위해 작동하지 않는 경우,이 컬렉션과 함께 할 것입니다 :
그런 다음 두 번째의 데이터로 첫 컬렉션에서 노드 ID를 대체 할 단순 반복 기능을 쓸 수 있습니다. 2 개 쿼리 간단한 클라이언트 측 처리.
작은 업데이트 :
당신은 좀 더 유연하게 두 번째 모음을 확장 할 수 있습니다 :
{_id : 2, 데이터 "무언가"아이들 [3, 7, 부모가 : [1, 12, 13}
이 방법 당신은 어떤 잎에서 검색을 시작할 수 있습니다. 그리고, 사용은 상단 또는 나무의이 부분의 바닥에 도착하는지도-줄일 수 있습니다.
-
==============================
2.당신은 (https://www.mongodb.com/blog/post/introducing-version-40-mongoose-nodejs-odm와) 지금이 작업을 수행 할 수 있습니다
당신은 (https://www.mongodb.com/blog/post/introducing-version-40-mongoose-nodejs-odm와) 지금이 작업을 수행 할 수 있습니다
var mongoose = require('mongoose'); // mongoose.Promise = require('bluebird'); // it should work with native Promise mongoose.connect('mongodb://......'); var NodeSchema = new mongoose.Schema({ children: [{type: mongoose.Schema.Types.ObjectId, ref: 'Node'}], name: String }); var autoPopulateChildren = function(next) { this.populate('children'); next(); }; NodeSchema .pre('findOne', autoPopulateChildren) .pre('find', autoPopulateChildren) var Node = mongoose.model('Node', NodeSchema) var root=new Node({name:'1'}) var header=new Node({name:'2'}) var main=new Node({name:'3'}) var foo=new Node({name:'foo'}) var bar=new Node({name:'bar'}) root.children=[header, main] main.children=[foo, bar] Node.remove({}) .then(Promise.all([foo, bar, header, main, root].map(p=>p.save()))) .then(_=>Node.findOne({name:'1'})) .then(r=>console.log(r.children[1].children[0].name)) // foo
몽구스없이 간단한 대안 :
function upsert(coll, o){ // takes object returns ids inserted if (o.children){ return Promise.all(o.children.map(i=>upsert(coll,i))) .then(children=>Object.assign(o, {children})) // replace the objects children by their mongo ids .then(o=>coll.insertOne(o)) .then(r=>r.insertedId); } else { return coll.insertOne(o) .then(r=>r.insertedId); } } var root = { name: '1', children: [ { name: '2' }, { name: '3', children: [ { name: 'foo' }, { name: 'bar' } ] } ] } upsert(mycoll, root) const populateChildren = (coll, _id) => // takes a collection and a document id and returns this document fully nested with its children coll.findOne({_id}) .then(function(o){ if (!o.children) return o; return Promise.all(o.children.map(i=>populateChildren(coll,i))) .then(children=>Object.assign(o, {children})) }); const populateParents = (coll, _id) => // takes a collection and a document id and returns this document fully nested with its parents, that's more what OP wanted coll.findOne({_id}) .then(function(o){ if (!o.parent) return o; return populateParents(coll, o.parent))) // o.parent should be an id .then(parent => Object.assign(o, {parent})) // replace that id with the document });
-
==============================
3.또 다른 방법은 Model.populate ()가 약속을 반환하고 다른 약속과 약속을 이행 할 수 있다는 사실을 활용하는 것입니다.
또 다른 방법은 Model.populate ()가 약속을 반환하고 다른 약속과 약속을 이행 할 수 있다는 사실을 활용하는 것입니다.
당신은 재귀를 통해 문제의 노드를 채울 수 있습니다 :
Node.findOne({ "_id": req.params.id }, function(err, node) { populateParents(node).then(function(){ // Do something with node }); });
populateParents는 다음과 같이 수 :
var Promise = require('bluebird'); function populateParents(node) { return Node.populate(node, { path: "parent" }).then(function(node) { return node.parent ? populateParents(node.parent) : Promise.fulfill(node); }); }
그것은뿐만 가장 성능이 좋은 방법입니다,하지만 N이 작은 경우이 작동합니다.
-
==============================
4.이제 몽구스 4이 수행 할 수 있습니다. 지금 당신은 하나의 레벨보다 더 깊은 재귀 수 있습니다.
이제 몽구스 4이 수행 할 수 있습니다. 지금 당신은 하나의 레벨보다 더 깊은 재귀 수 있습니다.
예
User.findOne({ userId: userId }) .populate({ path: 'enrollments.course', populate: { path: 'playlists', model: 'Playlist', populate: { path: 'videos', model: 'Video' } } }) .populate('degrees') .exec()
당신은 여기에서 몽구스 깊은 채우기위한 공식 문서를 찾을 수 있습니다.
-
==============================
5.나는 fzembow의 솔루션 @ 시도하지만 깊은 인구가 경로에서 개체를 반환하는 것 같았다. 내 경우에는 내가 재귀 적으로 객체를 채우는,하지만 매우 동일한 개체를 반환 할 필요가 있었다. 나는 그런 식으로했다 :
나는 fzembow의 솔루션 @ 시도하지만 깊은 인구가 경로에서 개체를 반환하는 것 같았다. 내 경우에는 내가 재귀 적으로 객체를 채우는,하지만 매우 동일한 개체를 반환 할 필요가 있었다. 나는 그런 식으로했다 :
// Schema definition const NodeSchema = new Schema({ name: { type: String, unique: true, required: true }, parent: { type: Schema.Types.ObjectId, ref: 'Node' }, }); const Node = mongoose.model('Node', NodeSchema); // method const Promise = require('bluebird'); const recursivelyPopulatePath = (entry, path) => { if (entry[path]) { return Node.findById(entry[path]) .then((foundPath) => { return recursivelyPopulatePath(foundPath, path) .then((populatedFoundPath) => { entry[path] = populatedFoundPath; return Promise.resolve(entry); }); }); } return Promise.resolve(entry); }; //sample usage Node.findOne({ name: 'someName' }) .then((category) => { if (category) { recursivelyPopulatePath(category, 'parent') .then((populatedNode) => { // ^^^^^^^^^^^^^^^^^ here is your object but populated recursively }); } else { ... } })
그것은 매우 효율적이 아니다 조심하십시오. 자주 또는 깊은 수준에서 같은 쿼리를 실행해야하는 경우에, 당신은 당신의 디자인을 재고해야
-
==============================
6.이 caub의 대답과 훌륭한 솔루션에 대한보다 정직 접근 방식입니다. 내가 함께이 버전을 넣어 그래서 조금 어려운 처음의 의미를 발견.
이 caub의 대답과 훌륭한 솔루션에 대한보다 정직 접근 방식입니다. 내가 함께이 버전을 넣어 그래서 조금 어려운 처음의 의미를 발견.
중요한, 당신은 일이 솔루션을 장소에 모두 'findOne'과 '발견'미들웨어 후크가 필요합니다. *
* 또한, 모델 정의는 미들웨어 정의 뒤에 와야합니다 *
const mongoose = require('mongoose'); const NodeSchema = new mongoose.Schema({ children: [mongoose.Schema.Types.ObjectId], name: String }); const autoPopulateChildren = function (next) { this.populate('children'); next(); }; NodeSchema .pre('findOne', autoPopulateChildren) .pre('find', autoPopulateChildren) const Node = mongoose.model('Node', NodeSchema) const root = new Node({ name: '1' }) const main = new Node({ name: '3' }) const foo = new Node({ name: 'foo' }) root.children = [main] main.children = [foo] mongoose.connect('mongodb://localhost:27017/try', { useNewUrlParser: true }, async () => { await Node.remove({}); await foo.save(); await main.save(); await root.save(); const result = await Node.findOne({ name: '1' }); console.log(result.children[0].children[0].name); });
from https://stackoverflow.com/questions/26041262/mongoose-recursive-populate by cc-by-sa and MIT license
'MONGODB' 카테고리의 다른 글
[MONGODB] MongoDB를 사용하여 산화 마그네슘의 효율적인 페이징 (0) | 2019.12.23 |
---|---|
[MONGODB] MongoDB를, $ 조회로 집계 쿼리 (0) | 2019.12.23 |
[MONGODB] 어레이 MongoDB의 형태 변화 (0) | 2019.12.23 |
[MONGODB] 몽고 개체를 사용하여 몽구스 빈 등의 설정 필드 (0) | 2019.12.23 |
[MONGODB] MongoNetworkError : 먼저 연결에 : [27017 로컬 호스트] 서버에 연결하는 데 실패 [MongoNetworkError : 연결 ECONNREFUSED 127.0.0.1:27017] (0) | 2019.12.23 |