Как сделать запрос, чтобы все документы ссылались на другую коллекцию на основе одного поля в качестве имени пользователя - PullRequest
0 голосов
/ 06 февраля 2020

В моем Node API и MongoDB я пытаюсь создать конечную точку для получения всех сообщений, связанных с одним именем пользователя профиля. В моей схеме профиля у меня есть ссылка на схему сообщений, а в моей схеме сообщений - ссылка на имя пользователя из схемы профиля. Моя проблема, я не знаю, как получить все сообщения для этого имени пользователя. Я сделал то же самое, но со встроенным для схемы Experience, но я не уверен, как это сделать для указанных коллекций.

Модель поста:

const { Connect } = require("../db");

const reactionSchema = {
    likedBy: {
        type: String,
        unique: true,
        sparse: true
    }
};

const postSchema = {
    text: {
        type: String,
        required: true,
        unique: true,
        sparse: false
    },    
    username: {
        type: Connect.Schema.Types.String,
        ref: "Profile"
    },    
    image: {
        type: String,
        default: "https://via.placeholder.com/150",
        required: false
    },
    createdAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    updatedAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    reactions: [reactionSchema],    
    comments: {
        type: Connect.Schema.Types.ObjectId,
        ref: "Comment",
        required: false
    }
};

const collectionName = "post";
const postSchemaModel = Connect.Schema(postSchema);
const Post = Connect.model(collectionName, postSchemaModel);

module.exports = Post;

Модель профиля:

// Here defining profile model
// Embedded we have the Experience as []
const { Connect } = require("../db");
const { isEmail } = require("validator");

const postSchema = {
    type: Connect.Schema.Types.ObjectId,
    ref: "Post"
};

const experienceSchema = {
    role: {
        type: String,
        required: true
    },
    company: {
        type: String,
        required: true
    },
    startDate: {
        type: Date,
        required: true
    },
    endDate: {
        type: Date,
        required: false
    },
    description: {
        type: String,
        required: false
    },    
    area: {
        type: String,
        required: true
    },
    createdAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    updatedAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    username: {
        type: String,
        required: false
    },
    image: {
        type: String,
        required: false,
        default: "https://via.placeholder.com/150"
    }
};

const profileSchema = {
    firstname: {
        type: String,
        required: true
    },   
    surname: {
        type: String,
        required: true
    },    
    email: {
        type: String,
        trim: true,
        lowercase: true,
        unique: true,
        required: [true, "Email is required"],
        validate: {
            validator: string => isEmail(string),
            message: "Provided email is invalid"
        }
    },    
    bio: {
        type: String,
        required: true
    },    
    title: {
        type: String,
        required: true
    },    
    area: {
        type: String,
        required: true
    },    
    imageUrl: {
        type: String,
        required: false,
        default: "https://via.placeholder.com/150"
    },    
    username: {
        type: String,
        required: true,
        unique: true
    },    
    experience: [experienceSchema],
    posts: [postSchema],    
    createdAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    updatedAt: {
        type: Date,
        default: Date.now,
        required: false
    }
};

const collectionName = "profile";
const profileSchemaModel = Connect.Schema(profileSchema);
const Profile = Connect.model(collectionName, profileSchemaModel);

module.exports = Profile;

Я смог сделать это для встроенного опыта, но не уверен, что это правильно для сбора ссылок:

const profileWithExperiences = await Student.aggregate([
  { $match: { username: res.username.username } },
  {
    $unwind: "$experience"
  },
  {
    $match: {
      "experience._id": new ObjectID(req.params.experienceId)
    }
  },
  {
    $project: {
      username: 1,
      experience: 1,
      _id: 0
    }
  }
]);

Я хотел бы увидеть пример для ссылочных коллекций, поскольку меня смущает, как мне это сделать

[EDIT] JSON для профилей и сообщений

{
    "_id": ObjectId("5e2c98fc3d785252ce5b5693"),
    "imageUrl": "https://i.pravatar.cc/300",
    "firstname": "Jakos",
    "surname": "Lemi",
    "email": "lemi@email.com",
    "bio": "My bio bio",
    "title": "Senior IT developer",
    "area": "Copenhagen",
    "username": "Jakos",
    "experience": [
        {
            "image": "https://via.placeholder.com/150",
            "_id": ObjectId("5e3975f95fbeec9095ff3d2f"),
            "role": "Developer",
            "company": "Google",
            "startDate": ISODate("2018-11-09T23:00:00.000Z"),
            "endDate": ISODate("2019-01-05T23:00:00.000Z"),
            "area": "Copenhagen",
            "createdAt": ISODate("2020-02-04T13:47:37.167Z"),
            "updatedAt": ISODate("2020-02-04T13:47:37.167Z")
        },
        {
            "image": "https://via.placeholder.com/150",
            "_id": ObjectId("5e3978bf5e399698e20c56d4"),
            "role": "Developer",
            "company": "IBM",
            "startDate": ISODate("2018-11-09T23:00:00.000Z"),
            "endDate": ISODate("2019-01-05T23:00:00.000Z"),
            "area": "Copenhagen",
            "createdAt": ISODate("2020-02-04T13:59:27.412Z"),
            "updatedAt": ISODate("2020-02-04T13:59:27.412Z")
        }
    ],
    "createdAt": ISODate("2020-01-25T19:37:32.727Z"),
    "updatedAt": ISODate("2020-02-04T23:14:37.122Z"),
    "__v": NumberInt("0")
}

Пост

{
    "_id": ObjectId("5e3beb639e072afedd19dcef"),
    "username": ObjectId("5e2c98fc3d785252ce5b5693"),
    "image": "https://via.placeholder.com/150",
    "text": "My awesome post",
    "createdAt": ISODate("2020-02-06T10:33:07.22Z"),
    "updatedAt": ISODate("2020-02-06T10:33:07.22Z"),
    "reactions": [ ],
    "__v": NumberInt("0")
}

Ожидаемый вывод:

{
    "username": "Jakos",
    "postsCount": [1],
    "posts": [
        {
        "_id": ObjectId("5e3beb639e072afedd19dcef"),
        "image": "https://via.placeholder.com/150",
        "text": "My awesome post",
        "createdAt": ISODate("2020-02-06T10:33:07.22Z"),
        "updatedAt": ISODate("2020-02-06T10:33:07.22Z"),
        "reactions": [ ],
        "__v": NumberInt("0")
    }
    ]

}

Я хочу просмотреть все сообщения, связанные с этим именем пользователя

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Вы можете использовать агрегацию $ lookup для объединения коллекций.

db.profiles.aggregate([
  {
    $match: {
      username: "Jakos"
    }
  },
  {
    $lookup: {
      from: "posts",   //the name of the posts collection, change this if it is different
      localField: "_id",
      foreignField: "username",
      as: "posts"
    }
  },
  {
    $project: {
      username: 1,
      posts: 1,
      postsCount: {
        $size: "$posts"
      },
      _id: 0
    }
  }
])

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

Для mongoose она должна выглядеть следующим образом: это в вашем приложении:

const profileWithExperiences = await Student.aggregate([
  { $match: { username: res.username.username } },
  {
    $unwind: "$experience"
  },
  {
    $lookup: {
      from: "posts", //the name of the posts collection, change this if it is different
      localField: "_id",
      foreignField: "username",
      as: "posts"
    }
  },
  {
    $project: {
      username: 1,
      posts: 1,
      postsCount: {
        $size: "$posts"
      },
      _id: 0
    }
  }
]);
0 голосов
/ 06 февраля 2020

Попробуй получить вот так: я получаю данные из двух таблиц с использованием node и mongodb.

var param = {};
    param['user_id']=id;
    var search={ user_id:param.user_id,status: [ 'Pending', 'Accepted' ] };
    var output={};
    output = await JobRequest.find(search); 
    if(output !=0)
    {
            var JSon=await JobRequest.aggregate([
                {$match: { user_id: {$gte:id}}  }, 
                     {
                     "$project": {
                      "employee_id": {
                        "$toObjectId": "$employee_id"
                      }, 
                      "service_id": {
                        "$toObjectId": "$service_id"
                      }, 
                      "createdDate": {
                        "$toString": "$createdDate"
                      }, 
                      "chat_status": {
                        "$toString": "$chat_status"
                      },    
                      "status": {
                        "$toString": "$status"
                      },                      
                      "delivery_address": {
                        "$toString": "$delivery_address"
                      },                 
                      "delivery_lat": {
                        "$toString": "$delivery_lat"
                      },         
                      "delivery_lang": {
                        "$toString": "$delivery_lang"
                      },
                    }
                     },

                     {
                      $lookup:
                         {
                            from: "employees",
                            localField: "employee_id",
                            foreignField: "_id",
                            as: "employee_details"
                        }
                   },
                   {
                      $lookup:
                         {
                            from: "services",
                            localField: "service_id",
                            foreignField: "_id",
                            as: "service_details"
                        }
                   }
               ]);
...