How to count multiple query results - mongodb

I have a document structure
var RelationshipSchema = new mongoose.Schema({
followee: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
follower: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
start: {
type: Date,
default: Date.now
},
end: {
type: Date
}
})
If i has a userId How would i query to count the followee and the follower for the same given userId.
and return the result?

Related

Is it possible to have two types of objects in an array of mongoose schema

I am building an e-commerce application and this is my orders schema.
const mongoose = require("mongoose");
const orderSchema = new mongoose.Schema({
buyer: {
type: mongoose.Schema.Types.ObjectId,
ref: "buyer",
required: true
},
items: [{
item: {
type: mongoose.Schema.Types.ObjectId,
ref: "item",
},
quantity: {
type: Number,
default: 1
}}
],
seller: {
type: mongoose.Schema.Types.ObjectId,
ref: "seller",
required: true
},
location: {
type: {
type: "String",
enum:['Point']
},
coordinates: {
type: [Number],
index: '2dsphere'
}
},
sendAt:{
type: Date,
default: Date.now
}
});
const orderModel = mongoose.model("orders", orderSchema);
module.exports = orderModel;
I want to have an array having item-reference-id and quantity.
But with the above schema when i enter data, each item is acting as an another sub-document and having _id. Query response image.
I have found solution:
order: [
{
_id: false,
item: {
type: mongoose.Schema.Types.ObjectId,
ref: "items",
required: true,
},
quantity: { type: Number },
},
],
_id: false will stop the subdocument from creating another id for the subdocument.

mongoose, match using upper model field in deep population

I'm a newbie in MongoDB and mongoose. and I'm trying to create a simple messenger using MongoDB.
Subscription model:
const SubscriptionSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'User',
index: { unique: true }
},
conversations: [
{
conversation: {
type: Schema.Types.ObjectId,
ref: 'Conversation'
},
lastSeenMessage: {
type: Schema.Types.ObjectId,
ref: 'Message'
}
}
]
});
Conversation model:
const ConversationSchema = new Schema(
...,
{ timestamps: true, toJSON: { virtuals: true } }
);
ConversationSchema.virtual('messages', {
ref: 'Message',
localField: '_id',
foreignField: 'conversation'
});
Message model:
const MessageSchema = new Schema(
{
content: {
type: String,
maxlength: [1440, 'Text too long.']
},
type: {
type: String
},
conversation: {
type: Schema.Types.ObjectId,
ref: 'Conversation'
},
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
}
)
I need to retrieve m latest conversations of user and n messages within each conversation when they are written after last seen message. So I used mongoose like this:
let subscription = await Subscription.findOne(
{ user }
//{ ObjectArray: { $slice: [(page - 1) * limit, (page - 1) * limit + limit] } }
).populate({
path: 'conversations.conversation',
model: 'Conversation',
populate: {
path: 'messages',
match: { _id: { $gt: 'conversations.lastSeenMessage' } },
options: {
skip: 0,
limit: 50,
sort: { updatedAt: -1 }
}
}
});
the match condition doesn't works in above query. how can use upper model in match condition in the deep population ?
Is it possible or I must try another way?

Collection referencing multiple collections

I want to have a collection with multiple fields referencing multiple collections, something like it:
var comboSchema = new Schema({
oneId: { type: Schema.Types.ObjectId, ref: "One" },
twoId: { type: Schema.Types.ObjectId, ref: "Two" },
threeId: { type: Schema.Types.ObjectId, ref: "Three" },
components: {
id: {type: Schema.Types.ObjectId, ref: "Component"},
amount: {type: Number}
}
}
I know I can use $lookup and aggregate to get data, but it looks like it works only on a single field in a collection?
Any help? Thank you! :-)
This is a model sample using the ref, the ref key in the object will take the name of the model in which you are referencing
const mongoose = require('mongoose');
const postSchema = mongoose.Schema({
text: {
type: String,
required: 1
},
mediatype: {
type: String,
required: 1
},
media: {
type: String,
required: true
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
likes: {
type: [{
userid: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
}
}]
},
comments: {
type: [{
userid: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
comment: String
}]
},
}, {
timestamps: true
})
const Post = mongoose.model('post', postSchema)
module.exports = Post
so you can then populate it like Post.find().populate('user')

Ordering two reference arrays together

Suppose I have the following schemas:
var QuizSchema = new mongoose.Schema({
name: { type: String, required: true },
questions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Question' }],
questionGroups: [{ type: mongoose.Schema.Types.ObjectId, ref: 'QuestionGroup' }]
});
var QuestionSchema = new mongoose.Schema({
number: { type: String, required: true }, // e.g. 1, a, i, anything
question: { type: String, required: true },
type: { type: String, enum: ['multiple choice', 'multiple select', 'short answer'] },
choices: [String],
answers: [String]
});
var QuestionGroupSchema = new mongoose.Schema({
number: { type: String, required: true }, // e.g. 1, a, i, anything
prompt: { type: String },
questions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Question' }]
});
I am trying to design a way that will allow me to order questions and question groups together.
I was thinking maybe of adding a new field order
var QuizSchema = new mongoose.Schema({
// ...
order: [
{
type: { type: String, enum: ['Question', 'QuestionGroup'] },
id: mongoose.Schema.Types.ObjectId // reference
}
]
});
such that in the database, the field would contain something such as
[
{ type: 'Question', id: ObjectId('57867a34567g67790') },
{ type: 'Question', id: ObjectId('57867a34567g67765') },
{ type: 'QuestionGroup', id: ObjectId('69864b64765y45645') },
{ type: 'Question', id: ObjectId('57867a34567g67770') },
{ type: 'QuestionGroup', id: ObjectId('69864b64767y45647') }
]
This may mean that I would need to "populate" the ordered list of questions and question groups as
quiz.populate('questions questionGroups').exec(function (err, quiz) {
// sort questions and groups by the order
quiz.order = quiz.order.map(function (o) {
if (o.type === 'QuestionGroup') {
return quiz.questionGroups.id(o.id);
}
return quiz.questions.id(o.id);
});
});
So my question: is there a better way to design this?
Virtuals can come in handy here; without persisting order field in db and doing calculations on client each time:
var QuizSchema = new mongoose.Schema({
name: { type: String, required: true },
questions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Question' }],
questionGroups: [{ type: mongoose.Schema.Types.ObjectId, ref: 'QuestionGroup' }]
},
{
toObject: {
virtuals: true
},
toJSON: {
virtuals: true
}
}
);
QuizSchema
.virtual('order')
.get(function() {
return this.questions.concat(this.questionGroups); //questions followed by questionGroups
});
Sort on createdAt is of course optional, but for that you need to have this field in Question and QuestionGroup:
Quiz.find({}, function (err, quiz) {
//...
})
.populate({path : 'questions', options: {sort: { 'createdAt': 1 }}})
.populate({path : 'questionGroups', options: {sort: { 'createdAt': 1 }}});

mongoose Foreign Key

I have a model called Portfolio that points to a user object using the user_id field. How can I model a many to one relationship with mongoose?
Portfolio
- user_id => is the id of a user object
Basically every portfolio object belongs to a user object.
I have the following code: Is this correct?
var PortfolioSchema = mongoose.Schema({
url: String,
createTime: { type: Date, default: Date.now },
updateTime: { type: Date, default: Date.now },
user:[
{type: Schema.Types.ObjectId, ref: 'User'}
]
});
Try this instead
var PortfolioSchema = mongoose.Schema({
url: String,
createTime: { type: Date, default: Date.now },
updateTime: { type: Date, default: Date.now },
user:{type: Schema.Types.ObjectId, ref: 'User'}
});