How to get join result using mongoose populate, match (2 collections) - node.js

User Schema
var UsersSchema = new Schema({
username:String,
city:String
},{collection:'User'});
//sample data {'username':'7700010000',city:'mumbai'}
College Schema
var College = new Schema({
college:String,
user_sess:[type:String,ref:"User"]},{collection:'College'});
//sample data {'college':'adarsh college','user_sess':'Sess$7700010000'}
I am trying to get result from college collection based on user_sess. but problem is user_sess has value with prefix value 'Sess$'
so user_sess = prefix + username from collection User
var prefix = 'Sess$';
College
.find({ "user_sess": prefix + req.body.user_id})
.populate({'user_sess'})
.exec(function (err, users) {
console.log();
if (err)
res.send(err);
res.json(users);
});
If there is a match for user_sess then result should look like
{'college':'adarsh college','username':'7700010000','city':'mumbai'}

I already solved it by adding reference keys in my respective collection because I i tried regex but it added extra latency in my responses. We are using parse server framework but we want to get rid of it but since parse saves data differently I was not able to do joins using mongoose schema.
Thank you.

Related

Insert multiple document with mongoose

I made an API with express.js, and i use mongoDB for my database and mongoose as my ODM
I really confused when i want to insert multiple document to my collection in once post request.
Here my model :
const modul = require('../config/require');
const Schema = modul.mongoose.Schema;
let TeleponSchema = new Schema({
_pelanggan : {type: String},
telepon: {type: String, required: true}
});
module.exports = modul.mongoose.model('telepon', TeleponSchema, 'telepon');
and here my controller
const Telepon = require('../models/telepon.model')
exports.create = (req,res) => {
let telepon = new Telepon({
_pelanggan : req.body.pel,
telepon: req.body.telepon
});
telepon.save((err,data) => {
if(err){
res.send({message:'eror', detail: err});
}else{
res.send({message:'success', data: data})
}
});
}
Then i post my request with postman like this :
but the result in my document is :
that's the problem, the value of 'telepon' is in the same row and separated by comma instead of insert a new row and create a new _id
i want the result of my collection like this :
(example)
Any help and suggestion would be much appreciated
Thank you!
1) Per .save call you will only affect one document, check out insertMany to do multiple.
2) req.body.telepon is either an array of numbers, or is already just the comma delimited list of numbers; if it is an array the .toString will result in a comma delimited list anyways. So when you new up the Telepon it has both values in one property, which is what you see in the result.

Building an api with several arrays which can be updated

I'm new to noSQL and i'm trying to figure out how to create the best possible model structure. What i need to do is every hour to retrieve leagues and matches from an api and add it to my database. Every hour the score might change and new matches might be added to each league and therefor this should be possible in the model. i've read the documentation and created following, however i'm not sure it is possible to update each and add new matches to leagues. What is the ideal modelling for such?
Tournament model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var League = require('./league');
var TournamentSchema = new Schema({
slug: String,
tournaments: [League]
});
module.exports = mongoose.model('Tournament', TournamentSchema);
League
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Match = require('./match');
var leagueSchema = new Schema({
leaguetId: Number,
name: String,
matches: [Match]
});
module.exports = mongoose.model('League', leagueSchema);
Match
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var matchSchema = new Schema({
homeTeam: String,
awayTeam: String,
homeScore: Number,
awayScore: Number,
start: Date
});
module.exports = mongoose.model('Match', matchSchema);
Post request so far
router.post('/tournaments', function(req, res, next) {
var tournament = new Tournament(); // create a new instance of the Bear model
tournament.name = req.body.slug; // set the bears name (comes from the request)
// save the bear and check for errors
tournament.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Tournament created!' });
});
});
If you're adding new matches to leagues and updating matches on a timed interval, why nest them within each other? Lets say you have a match with id 5 whose score changed. In order to find it to update it you'd have to first go through each league, and then iterate through each match in each league until you find the match with id 5. Unless I'm mistaken and there's some easier way to do it, this seems very inefficient.
Why not have two collections? A league collection and a match collection. There will be a 1 (league) : many (match) relationship. When you need to update a match's score, who cares what league it's in? Search the match collection for id 5, and update it.
What would a new match look like? Lets say a league with id 7 had a new match. Add a match to the match collection that has a league id of 7.
If you're really opposed to moving away from one collection.. at least store your matches in an object instead of an array, that way you can find matches with an O(1) lookup time by using it's match name. Instead of O(n) or O(n^2) lookup time like you currently have.

Getting all documents from MongoDB instead of all Models

I'm calling MongoDB from my Node app using Mongoose like this:
var query = itemModel.find();
query.exec(function (err, items) {
console.log(err);
socket.emit("items", items);
});
I have 3 models defined like this:
var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
var playerModel = require('./models/player.js').make(Schema, mongoose);
var characterModel = require('./models/character.js').make(Schema, mongoose, ObjectId);
var itemModel = require('./models/item.js').make(Schema, mongoose);
my models look like this:
function make(Schema, mongoose) {
itemSchema = new Schema({
name: String
, bonus: [{
type: String
, value: Number
}]
, price: Number
, slot: String
});
return mongoose.model('Character', characterSchema);
}
exports.make = make;
For some reason I'm getting all documents, regardless of them being items, characters or players. Since I'm calling find() on itemModel I was expecting only Items, what am I doing wrong?
The model that you have shown appears to be the item model, but you are creating the model with the 'Character' name. This means that you told Mongoose about the scheme for an item and that it is stored in the 'character' collection. Assuming you've done the same for each other model (Character/Player), you've been Mongoose that everything is in the same collection.
Then you query that collection and you seem surprised that everything is stored in the same collection. It strikes me as if you have little experience with Mongoose/MongoDB, so I will suggest you download and learn to love MongoVUE. This application is a good GUI to see what is going on under the hood of the MongoDB database. While developing, you also might want to enable debugging so you can see what queries mongoose is launching to the server (mongoose.set('debug', true)).

Nested models mongoose with nodejs generates duplicates

here is my code for models.js where I keep models
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
var GroupSchema = new Schema({
title : String
, elements : [ElementSchema]
, author : String
});
var ElementSchema = new Schema({
date_added : Date
, text : String
, author : String
});
mongoose.model('Group', GroupSchema);
exports.Group = function(db) {return db.model('Group');};
mongoose.model('Element', ElementSchema);
exports.Element = function(db) { return db.model('Element');
};
To me it looks pretty clear, but when I do
function post_element(req, res, next) {
Group.findOne({_id: req.body.group}, function(err, group) {
new_element = new Element({author: req.body.author,
date_added: new Date()});
new_element.save();
group.elements.push(new_element);
group.save();
res.send(new_element);
return next();
})
}
I don't understand why when I go in Mongo I have two collections one called Groups with nested groups (so it looks fine) and the other collection is called Elements.
Why? Shouldn't it be called just Group ?
I don't understand, a good chap that please explain it to me?
Thanks,
g
When you execute this line:
new_element.save();
you're saving the newly created element to the Elements collection. Don't call save on the element and I think you'll get the behavior you're looking for.
Its because of the following line:
mongoose.model('Element', ElementSchema);
This registers a model in mongoose and when you register a model, it will create its own collection inside mongo. All you have to do is get rid of this line and you will see it disappear.
On another note, its much cleaner and easier to setup your files to only export one model per file using the following to export the model:
module.exports = mongoose.model('Group', GroupSchema);
Hope this helps!

finding objectIds between two given values in mongodb and nodejs

I am creaing schemas similar to newsposts with an option for users to like and dislike them.
Here are the schemas for same
Client= new mongoose.Schema({
ip:String
})
Rates = new mongoose.Schema({
client:ObjectId,
newsid:ObjectId,
rate:Number
})
News = new mongoose.Schema({
title: String,
body: String,
likes:{type:Number,default:0},
dislikes:{type:Number,default:0},
created:Date,
// tag:String,
client:ObjectId,
tag:String,
ff:{type:Number,default:20}
});
var newsm=mongoose.model('News', News);
var clientm=mongoose.model('Client', Client);
var ratesm=mongoose.model('Rates', Rates);
In order to retreive the ratingsgiven by a particular user having given a set of newsposts, I tried,
newsm.find({tag:tag[req.params.tag_id]},[],{ sort:{created:-1},limit: buffer+1 },function(err,news){
ratesm.find({
client:client._id,
newsid:{$lte:news[0]._id,$gte:news.slice(-1)[0]._id}
},
function(err,ratings){
})
})
This query returns empty list no matter what. I doubt whether $gte and $lte be used to compare objectIds. Am I right? How can I which posts a user has liked/disliked in a given set of newsposts?
Yes, ObjectIds can be queried with range queries like $gt/$lt etc. Can you post the exact values being used for news[0]._id and news.slice(-1)[0]._id that are giving you the empty result?
However, i'm not sure that $gt/$lt is what you want here. It seems like what you need to do is extract the _ids of the news items, and then use that in a $in filter in your query on ratesm.

Resources