I want to display list files of particular user (_id: 876896) with their click counts as below:
Sr. No. | File Name | Click Count
Below is the sample schema I am using:
var clicks = mongoose.Schema({
file_id : String,
IP : String
});
var files = mongoose.Schema({
filename : String,
owner : {type:mongoose.Schema.ObjectId, ref:'users'},
});
How effectively this can done.
You can do it in two step, first get all files that refer to the users you want data for. Then, get alls clicks that are related to files you read.
There is no INNER_JOIN in mongodb
Little example:
files.find({
owner: {
$in: usersIdsArray // [_id, _id...] ids of all users
},
}).then((ret = []) => {
// Here ret is array of files
if (!ret.length) // There is no files matching the user
return clicks.find({
file_id: {
$in: Array.from(ret, x => x._id.toString()),
// build an array like [_id, _id, _id...]
},
});
}).then((ret = []) => {
// Here you have all clicks items
});
I also recommend to use embedded schema instead of multiple collections:
var clicks = mongoose.Schema({
file_id: String,
IP: String
});
var files = mongoose.Schema({
filename: String,
owner: {type:mongoose.Schema.ObjectId, ref:'users'},
});
turn into:
var files = mongoose.Schema({
filename: String,
owner: {type:mongoose.Schema.ObjectId, ref:'users'},
clicks: [String], // With String your IP
});
MongoDB is good when it comes to big data, but not that good in relations.
Related
I am just learning Mongoose and NodeJS. Attempting my own project after finishing a tutorial.
I have two Models: "Flat" (containing flat numbers) and "User" (users owning the Flats).
var flatsSchema = new mongoose.Schema({
flat: String,
users:[{
userId: String,
username: String,
userType: String //owner or tenant
}]
});
var Flat = new mongoose.model("Flat", flatsSchema);
var userSchema = new mongoose.Schema({
username: String,
flatsRegistered: [{
flat: String,
userType: String //owner or tenant
}]
});
var User = new mongoose.model("User", userSchema);
A User may own multiple Flats, and in each Flat, there can be multiple users.
In the "Flat" model, I have the users living in each flat in the "users" property. I also have flats owned by the users in the flatsRegistered property of "User" model.
Now when a user logs in to his webpage - I want to pass all the details of the flats he is registered to - with all the other users in those flats.
I tried the
flatsRegistered.foreach((userFlat) => {
Flat.findOne({ flat: userFlat }, function (err, flatFound) {
if (!err) {
console.log(flatFound.users) //assign flatFound.users to a variable which i pass to webpage using ejs
}
});
}
Trouble is the foreach loop completes before the Flat.findOne can complete. Is there any way to force Flat.findOne to complete before foreach can continue? After reading up things, I am discovering concepts of async/await and promise - but I really don't know how to use those (and even if they are applicable). Please help.
Just use for of with await like this:
for (const userFlat of flatsRegistered) {
const flatFound = await Flat.findOne({ flat: userFlat });
console.log(flatFound.users) //assign flatFound.users to a variable which i pass to webpage using ejs
}
I have a two Mongoose collection "File" and "FileShare".The schema details as below
var FileSchema = new mongoose.Schema({
name: { type: String},
shares: [ { type: Schema.Types.ObjectId, ref: "FileShare" } ]});
var FileShareSchema = new mongoose.Schema({
_id: Number,
user: { type: String }});
Sample Data for File Collection
name shares
================================
Document1.txt [1,2]
Document2.txt [1]
Document3.txt [2]
Document4.txt []
Sample Data for FileShare Collection
_id user
========================
1 John
2 Raj
I want write a query to get the list files which are shared with user. And also need to handle paging using query.
Expexted Result
For User John should get Document1.txt,Document2.txt
and User Raj should get Document1.txt,Document3.txt
File.find({})
.populate('FileShare')
.sort({'_id': 1})
.skip(0).limit(25)
.exec(function (err, files) {
res.send(files);
});
Please let me know is there any way to get this result using mongoose query.
Let's say I have a User and Group model, groups have users, like
var GroupSchema = mongoose.Schema({
name: String,
users: [{ type: mongoose.Schema.ObjectId, ref: 'User' }]
});
How would I query to get all the Users but exclude the ones that are on
Group.users, I'm already doing this by querying first Group then manually filtering against all users
var groupP = Group.findById(group_id).populate('users');
var userP = User.find();
Promise.props({
group: groupPromise.exec(),
users: usersPromise.exec()
})
.then(function (result) {
//this gives the expected result but I'm looking for a more straight forward mongoose only solution if possible
var users = differenceWith(result.users, result.group.users, (a, b) => { return a._id.toString() == b._id.toString()});
})
You can try below query.
var groupP = Group.findById(group_id);
var userP = User.find({_id:{$nin:groupP.users}});
Allora, I'm using mongoose for the first time and I decided to create 2 schemes: the first one represents a user and the second one represents his enquires. Users have an array of enquires like:
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [Enquire.schema] , "default" : [] },
});
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
I see that if I search for an enquire and update its status, it doesn't update the same enquire on the user's array, meaning that they are different object. I don't want to save an array of IDs as it will be the same as a relational database, so I see only 1 solution which is forgetting about the enquire scheme and use only the User scheme. Is it the way mongoose works? For every relationship do I have to insert everything like nested object?
I think you should use references to achieve what you want to achieve.
For more information on mongoose references and populate see Mongoose Populate documentation.
Try this, It may help you.
User Schema :
var userSchema = new mongoose.Schema({
name: String,
enquires: [{ type : mongoose.Schema.Types.ObjectId , ref : 'Enquiry' }]//array of enquiries
});
var User = mongoose.model('User',userSchema );
module.exports = User;
Enquiry Schema :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var Enquiry = mongoose.model('Enquiry',enquireSchema );
module.exports = Enquiry ;
Working :
create a new Enquiry.
Push it's ID(_id) into user's enquires array.
var enquiry = new Enquiry();
enquiry.enquire = "Dummy enquiry";//set the enquiry
enquiry.save(function(err,result){
if(!err){
//push 'result._id' into users enquires array
}
});
whenever you update an enquiry, it will be automatically updated in
user's document.
use populate to retrieve user's enquiries.
You can embed sub documents (entity) which has id and is like a document or embed native array like a normal property.
And I think the correct definition for yours is :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [enquireSchema] , "default" : [] },
});
If you use refs in embedded link then there are two separate collections and be like relational db's.
I am designing a MEAN (MongoDb + Express.js + Angular.js + Node.js) app.
The application actors are users and persons; currently there are ~1000 persons and ~100 users.
The users are the application registered users, and the persons are external people the users need to be informed of.
Each user is able to rate and take some notes about any person she is interested in.
The database schemas I'm planning are:
var person = new mongoose.Schema({
name: String,
phone: String,
...
};
var user = new mongoose.Schema({
name: String,
email: String,
...
},
var userToPersonSchema = new mongoose.Schema({
userId: { type: ObjectId , required: true },
personId: { type: ObjectId, required: true },
rating: Number,
notes: String,
...
});
This is the query I plan to add user rating for a person:
db.userToPerson.insert({
userId: currentUserId,
personId: currentPersonId,
rating: 10,
notes: 'my preferred person!'
});
This is the code I have to find all persons with a rating by a user:
var currentUserId = '123...';
var personsAll = db.person.find();
var usersToPersonsAll = db.userToPerson.find({ _id: currentUserId });
var personsRatedByCurrentUser = [];
for (var p = 0; p < personsAll.length; p++) {
for (var u = 0; u < usersToPersonsAll.length; u++) {
if (personsAll[p]._id === usersToPersonsAll[u].personId) {
personsRatedByCurrentUser.push(personsAll[p]);
}
}
}
The question:
for the last "query" I suppose I'd better use some form of aggregation, but I can't find out any...
Any advise about a schema design modification should be welcome, too, of course...
Any time I need a join in MongoDB, I break the problem into two queries.
First, fetch the ids from the first collection using distinct. Distinct just returns an array of unique values.
Then, query the second collection for documents corresponding to those ids. The $in parameter conveniently takes an array.
var currentUserId = '123...';
var personIds = db.userToPerson.distinct("personId", { _id: currentUserId });
var personsRatedByCurrentUser = db.person.find({ _id: {$in, personIds}});