mongoDB объединяет 2 коллекции - PullRequest
0 голосов
/ 27 апреля 2020

Я пытаюсь объединить двоих в коллекцию. Первый список фильмов:

[
  {
    "_id": "movie:1",
    "actors": [
      {
        "_id": "artist:15",
        "role": "John Ferguson"
      },
      {
        "_id": "artist:16",
        "role": "Madeleine Elster"
      },
      {
        "_id": "artist:282",
        "role": null
      }
    ],
    "country": "DE",
    "director": {
      "_id": "artist:3"
    },
    "genre": "drama",
    "summary": "Scottie Ferguson, ancien inspecteur de police, est sujet au vertige depuis qu'il a vu mourir son collègue. Elster, son ami, le charge de surveiller sa femme, Madeleine, ayant des tendances suicidaires. Amoureux de la jeune femme Scottie ne remarque pas le piège qui se trame autour de lui et dont il va être la victime... ",
    "title": "Vertigo",
    "year": 1958
  },
  {
    "_id": "movie:2",
    "actors": [
      {
        "_id": "artist:5",
        "role": "Ripley"
      }
    ],
    "country": "USA",
    "director": {
      "_id": "artist:4"
    },
    "genre": "Science-fiction",
    "summary": "Près d'un vaisseau spatial échoué sur une lointaine planète, des Terriens en mission découvrent de bien étranges \"oeufs\". Ils en ramènent un à bord, ignorant qu'ils viennent d'introduire parmi eux un huitième passager particulièrement féroce et meurtrier. ",
    "title": "Alien",
    "year": 1979
  },
  {
    "_id": "movie:5",
    "actors": [
      {
        "_id": "artist:11",
        "role": "Sean Archer/Castor Troy"
      },
      {
        "_id": "artist:12",
        "role": "Castor Troy/Sean Archer"
      }
    ],
    "country": "USA",
    "director": {
      "_id": "artist:10"
    },
    "genre": "Action",
    "summary": "Directeur d'une unité anti-terroriste, Sean Archer recherche Castor Troy, un criminel responsable de la mort de son fils six ans plus tôt. Il parvient à l'arrêter mais apprend que Troy a caché une bombe au Palais des Congrès de Los Angeles. Seul le frère de Troy peut la désamorcer et, pour l'approcher, Archer se fait greffer le visage de Troy. ",
    "title": "Volte/Face",
    "year": 1997
  },
  {
    "_id": "movie:4",
    "actors": [],
    "country": "FR",
    "director": {
      "_id": "artist:9"
    },
    "genre": "drama",
    "summary": null,
    "title": "Sacrifice",
    "year": 1986
  },
  {
    "_id": "movie:3",
    "actors": [
      {
        "_id": "artist:109",
        "role": "Rose DeWitt Bukater"
      },
      {
        "_id": "artist:110",
        "role": "Jack Dawson"
      }
    ],
    "country": "USA",
    "director": {
      "_id": "artist:6"
    },
    "genre": "drama",
    "summary": "Conduite par Brock Lovett, une expédition américaine fouillant l'épave du Titanic remonte à la surface le croquis d'une femme nue. Alertée par les médias la dame en question, Rose DeWitt Bukater, aujourd'hui centenaire, rejoint les lieux du naufrage, d'où elle entreprend de conter le récit de son fascinant, étrange et tragique voyage... ",
    "title": "Titanic",
    "year": 1997
  },
 {
    "_id": "movie:19",
    "actors": [
      {
        "_id": "artist:44",
        "role": "Terminator"
      }
    ],
    "country": "USA",
    "director": {
      "_id": "artist:6"
    },
    "genre": "Science-fiction",
    "summary": "Deux creatures venues du futur debarquent sur terre. L'une d'entre elles, le Terminator, doit eliminer une certaine Sarah Connor, qui doit enfanter celui qui sera le chef d'un groupe de resistants. L'autre, Kyle Reese, est charge par les rebelles de defendre Sarah... ",
    "title": "Terminator",
    "year": 1984
  },
…

Вторая коллекция была составлена ​​каждым художником (художник мог быть художником и / или режиссером):

[
  {
    "_id": "artist:1",
    "birth_date": "1971",
    "first_name": "Sofia",
    "last_name": "Coppola"
  },
  {
    "_id": "artist:2",
    "birth_date": null,
    "first_name": "Kirsten",
    "last_name": "Dunst"
  },
  {
    "_id": "artist:3",
    "birth_date": "1899",
    "first_name": "Alfred",
    "last_name": "Hitchcock"
  },
  {
    "_id": "artist:4",
    "birth_date": "1937",
    "first_name": "Ridley",
    "last_name": "Scott"
  },
  {
    "_id": "artist:5",
    "birth_date": "1949",
    "first_name": "Sigourney",
    "last_name": "Weaver"
  },
  {
    "_id": "artist:6",
    "birth_date": "1954",
    "first_name": "James",
    "last_name": "Cameron"
  },
  {
    "_id": "artist:7",
    "birth_date": "1973",
    "first_name": "Richard ",
    "last_name": "Fleischer"
  },
  {
    "_id": "artist:8",
    "birth_date": "1923",
    "first_name": "Charlton ",
    "last_name": "Hestone"
  },
  {
    "_id": "artist:9",
    "birth_date": "1932",
    "first_name": "Andrei",
    "last_name": "Tarkovski"
  },

Я бы хотел бы узнать фильм, снятый каждым режиссером, что-то вроде этого:

[{"first_name": "James", "last_name": "Cameron", "films": ["Titanic", "Terminator"]},
 …
]

Я делаю следующую просьбу:

db.artists.aggregate([
   {$lookup: {from: "jointure",
              localField: "artists._id",
               foreignField : "movies.director",
               as: "films"}
    },
    {$project: {"_id":0,
                "first_name": 1,
                "last_name": 1,
                "films.title" : 1}
    }
]);

и результат не верный (у меня все фильмы режиссер, а не только фильм, снятый режиссером):

{
    "films": [
      {
        "title": "Sacrifice"
      },
      {
        "title": "Alien"
      },
      {
        "title": "Titanic"
      },
      {
        "title": "Volte/Face"
      },
      {
        "title": "American Beauty"
      },
      {
        "title": "Sleepy Hollow"
      },
      {
        "title": "Vertigo"
      },
      {
        "title": "Piège de cristal"
      },
      {
        "title": "Impitoyable"
      },
      {
        "title": "58 minutes pour vivre"
      },
      {
        "title": "Van Gogh"
      },
      {
        "title": "Seven"
      },
      … 
   ],
    "first_name": "James",
    "last_name": "Cameron"
  },

Кажется, что у каждого режиссера есть все фильмы.

Подробнее:

У меня есть решение с картой / уменьшением но я не удовлетворен (и это устарело с 4.2):

var mapJoin = function() {
if (this._id.indexOf("artist") != -1) {
 this.type="artist";
 emit(this._id, this);
}
else {
 this.type="film";
 delete this.summary;
 delete this.actors;
 emit(this.director._id, this);
}
}

var reduceJoin = function(id, items) {
var director = null, films={result: []}
for (var idx = 0; idx < items.length; idx++) {
 if (items[idx].type=="artist") {
 director = items[idx];
 }
}
for (var idx = 0; idx < items.length; idx++) {
 if (items[idx].type=="film" && director != null) {
 items[idx].director = director;
 films.result.push (items[idx]);
 }
}
return films;
};

db.jointure.mapReduce(mapJoin, reduceJoin, {out: {"inline": 1}});

1 Ответ

0 голосов
/ 28 апреля 2020

Я не уверен, каким должно быть 'jointure'.

Если у вас есть коллекции actors и movies с документами, которые вы показываете в этом примере, простого $lookup должно быть достаточно :

db.artists.aggregate([
  {$lookup: {
      from: "movies",
      localField: "_id",
      foreignField: "director._id",
      as: "films"
  }},
  {$project: {
      "_id": 0,
      "first_name": 1,
      "last_name": 1,
      "films.title": 1
  }}
])

Если вы хотите, чтобы артисты имели хотя бы один фильм, добавьте в конце $match сцену, например

  {$match: {
      $expr: {
        $gt: [
          {$size: "$films"},
          0
        ]
      }
  }}

Детская площадка

...