2016-08-25 4 views
2

개체를 검색하고 관계 및 중첩 관계를 가져와야합니다.돛/물줄기 : 관계 내부의 관계를 검색하는 방법?

사용자 모델 :

module.exports = { 

    attributes: { 
    name: { 
     type: 'string' 
    }, 
    pets: { 
     collection: 'pet', 
     via: 'owner', 
    } 
} 

애완 동물 모델 :

module.exports = { 
    attributes: { 
    name: { 
     type: 'string' 
    }, 
    owner: { 
     model: 'user' 
    }, 
    vaccines: { 
     collection: 'vaccine', 
     via: 'pet', 
    } 
} 

백신 모델 :

module.exports = { 
    attributes: { 
    name: { 
     type: 'string' 
    }, 
    pet: { 
     model: 'pet' 
    } 
} 

가 호출 User.findOne(name: 'everton').populate('pets').exec(....) I

그래서, 나는 아래의 세 가지 모델이 너를 구해라. ser 및 관련 애완 동물. 각 백 와 관련된 백신을 어떻게 받습니까?? 공식 문서에서 이에 대한 참고 문헌을 찾지 못했습니다.

답변

1

나는이 문제에 대해서도 만났으며, 알고있는 한 중첩 된 연관 검색어는 아직까지 (이 게시물과 같이) 돛에 내장되어 있지 않습니다.

약속을 사용하여 중첩 된 인구를 처리 할 수 ​​있지만 많은 수준을 채우는 경우 다소 번거로울 수 있습니다. 같은

뭔가 :이 sails.js에 널리 논의 주제 왔으며이 기능의 대부분을 추가 오픈 풀 요청이 실제로있다

User.findOne(name: 'everton') 
    .populate('pets') 
    .then(function(user) { 
    user.pets.forEach(function (pet) { 
     //load pet's vaccines 
    }); 
    }); 

. 체크 아웃 https://github.com/balderdashy/waterline/pull/1052

+1

감사합니다. @Kevin! 글쎄, 내가 지시 한대로이 방법을 구현할 것이다. 마침내이 기능을 프레임 워크에 추가하면 업데이트 할 것입니다. –

1

Kevin Le의 답이 맞지만 루프 내에서 비동기 함수를 실행하고 있기 때문에 약간 지저분 할 수 있습니다. 물론 작동하지만 일단 완료되면 모든 애완 동물과 백신을 가지고 사용자를 돌려주고 싶다고합시다. 어떻게해야합니까?

이 문제를 해결하는 방법은 여러 가지가 있습니다. 하나는 async library을 사용하여 비동기 코드로 작업 할 수있는 많은 util 함수를 제공하는 것입니다. 라이브러리는 이미 돛에 포함되어 있으며 기본적으로 전역으로 사용할 수 있습니다.

User.findOneByName('TestUser') 
    .populate('pets') 
    .then(function (user) { 

    var pets = user.pets; 

    // async.each() will perform a for each loop and execute 
    // a fallback after the last iteration is finished 
    async.each(pets, function (pet, cb) { 

     Vaccine.find({pet: pet.id}) 
     .then(function(vaccines){ 

      // I didn't find a way to reuse the attribute name 
      pet.connectedVaccines = vaccines; 

      cb(); 
     }) 

    }, function(){ 
     // this callback will be executed once all vaccines are received 
     return res.json(user); 
    }); 
    }); 

이 문제를 해결할 수있는 대체 방법은 돛의 일부인 bluebird 약속입니다. 그것은 단지 하나의 데이터베이스 요청으로 모든 백신을 가져 오기 때문에 아마 이전의 것보다 더 효과적 일 것입니다. 다른 한편으로는 그것을 읽는 것이 더 어렵습니다 ...

User.findOneByName('TestUser') 
    .populate('pets') 
    .then(function (user) { 

    var pets = user.pets, 
     petsIds = []; 

    // to avoid looping over the async function 
    // all pet ids get collected... 
    pets.forEach(function(pet){ 
     petsIds.push(pet.id); 
    }); 

    // ... to get all vaccines with one db call 
    var vaccines = Vaccine.find({pet: petsIds}) 
     .then(function(vaccines){ 
     return vaccines; 
     }); 

    // with bluebird this array... 
    return [user, vaccines]; 
    }) 

    //... will be passed here as soon as the vaccines are finished loading 
    .spread(function(user, vaccines){ 

    // for the same output as before the vaccines get attached to 
    // the according pet object 
    user.pets.forEach(function(pet){ 

     // as seen above the attribute name can't get used 
     // to store the data 
     pet.connectedVaccines = vaccines.filter(function(vaccine){ 
     return vaccine.pet == pet.id; 
     }); 
    }); 

    // then the user with all nested data can get returned 
    return res.json(user); 

    }); 
+0

고마워요 @ 사이먼, 나는이 접근법도 시도 할 것입니다. –

관련 문제