How bind search values in mongodb with mongoose - javascript

I have the following code in my /search/:query route:
var param = {
query: req.query['query']
}
MyModel.find({
"$or": [
{ 'name': req.param.query },
{ 'age': req.param.query },
{ 'event': req.param.query },
]
}, function (err, results) {
if (err) {
console.log(err)
}
else {
res.render('index', {
data: results
});
}
}
);
And is good, i can search for pretty much every data that i want, but only individually. What if i want search name + age, can i? Example: 'Leo 22'.
There is any way that mongoose help me with this?
UPDATE:
My problem is:
I have tables lists it titles, this title is the concatenation of 'eventName' and 'eventDate'.
Real examples of this fields:
'Special Event - 20/12/2015'
'Classic Event - 12/03/2015'
'Hot Summer Event - 05/07/2005'
Every week will be create 4 events. In some point, a user will search for an old event, and i believe that the user will search in this format:'EVENT NAME - EVENT DATE'..
So i need a way to bind this values in my controllers.

I'm no familiar with mongoose but in order to do that, you must have a way to bind your query param to the attribute you want to search. Otherwise, they wouldn't know Leo is name and 22 is age.
Ur path would be like search?name=:name&age=:age&event=:event and in your code, you will have to process like if the param is not null, add and condition to it.

It seems you are using only one parameter (req.param.query) to filter all attributes. That's not mongoose related: you could create distinct parameters for each attribute and pass them along the query string.
For instance:
"$or": [
{ 'name': req.param.name },
{ 'age': req.param.age },
{ 'event': req.param.event },
]
And your HTTP request will be like this:
http://youraddress/expressRoute?name=Leo&age=22

Related

MongoDB - Comment Upvoting/Downvoting with Aggregation Pipeline

I'm trying to implement an upvote/downvote mechanism for comments (similar to the upvoting/downvoting mechanism found on reddit). I have a separate collection called commentReputation and the documents inside can look like this:
{
"_id" : ObjectId("5e5acb6d6034a879655c8819"),
"commentId" : ObjectId("5e5983102328a83d1a4b541f"),
"creationDate" : ISODate("2020-02-29T20:37:01.509Z"),
"upvotes" : [
ObjectId("5e5983102328a83d1a4b53e7"),
ObjectId("5e5983102328a83d1a4b53e4")
],
"downvotes" : [
ObjectId("5e5983102328a83d1a4b53e5")
]
}
In short: every comment will eventually have it's own CommentReputation document (the CommentReputation document should be created as soon as someone upvotes/downvotes a comment)
There are 2 case scenarios:
The collection is empty meaning that I need to create my very first CommentReputation document with a given commentId x. In some other part of the project I was using $setOnInsert with { upsert: true } but it seems (looking at the documentation) that the aggregation pipeline does not support $setOnInsert as for now. Is there another way to deal with this problem?
The document is there and the actuall upvoting should occur.
a) Both upvotes and downvotes arrays do not contain the userId that is trying to upvote thus it gets added to the upvotes array without any further actions
b) The upvotes array contains the userId that is trying to upvote the comment as a result the userId should be REMOVED from the upvotes array. (the user already had this comment upvoted and clicked a second time the upvote button which cancels out the upvote)
c) The downvotes array contains the userId. In this case the userId should be removed from downvotes and added to upvotes
I'm trying to accomplish the above logic with the updateOne method and a aggreagtion pipeline however I'm not sure if this is even possible.
What I currently have is returning a "Unrecognized pipeline stage name: '$cond'"
const updateUpvotes = {
$cond: {
if: { $elemMatch: { upvotes: ObjectID(userId) } },
then: { $pull: { upvotes: ObjectID(userId) } },
else: { $addToSet: { upvotes: ObjectID(userId) } }
}
};
db.collection(collectionName).updateOne({
commentId: ObjectID('5e5983102328a83d1a4b541f')
}, [updateUpvotes])
Am I overthinking the whole feature? I guess the 1. problem can be solved by simply creating a CommentReputation document (with empty upvotes and downvotes at the same time the Comment document is being created.
Is there a better way of doing this? I would love to have it working inside a single query request. Maybe someone of You guys implemented a similar feature and can give me some hints on this one.
you can do it with the following pipeline update but it requires that the upvotes and downvotes arrays exist. even if it's just empty.
var comment_id = ObjectId("5e5983102328a83d1a4b541f");
var user_id = ObjectId("5e5983102328a83d1a4b53e5");
db.commentReputation.update(
{
commentId: comment_id
},
[
{
$set: {
upvotes: {
$cond: [
{ $in: [user_id, '$upvotes'] },
{ $setDifference: ['$upvotes', [user_id]] },
{ $setUnion: ['$upvotes', [user_id]] }
]
}
}
},
{
$set: {
downvotes: {
$cond: [
{ $in: [user_id, '$downvotes'] },
{ $setDifference: ['$downvotes', [user_id]] },
'$downvotes'
]
}
}
}
]
);

Making a JOIN WHERE key IN(SELECT key FROM...) using Sequelize.js

Im a noob in Sequelize.js and somewhat less in Angular but must solve a problem in which I want to use a subquery as a condition of a JOIN. I paste some examples below because code says more then words.
SQL
INNER JOIN table ON table.key IN(SELECT current_key FROM historysnake WHERE original_key IN(
SELECT original_key FROM historysnake WHERE current_key = table.key)
AND historysnake.model = 'tablename')
The question is: How can I put above query into a Sequelize object? Something like:
Sequelize.js
var foo = sequelize.define('foo', {...}, {
classMethods: {
associate: function(models) {
foo.hasMany(...)
}
}
});
Ok, here's an example, which assumes that PK of PatientEvents is the original_key on all the history rows:
PatientEvents.hasMany(HistorySnake, {foreignKey : 'original_key'});
PatientEvents.findAll({
include: [{
model: HistorySnake,
required : true, // true = INNER JOIN but you might need outer join to see events with no history
where : { modelName : 'PatientEvents' } // as needed
}],
where: { patient_name : 'xyz' } // as needed
})
I figured it out. I'm not really sure if #KenOn10's answer would've worked. I'm too much of a noob on this subject for that but thanks for the answer anyway.
I ended up specifying my own 'on' clause like this.
models.Aim.find({
include: [{
model: models.ObjectiveReport,
required: false,
where: ['ObjectiveReports.report_entrydate >= ?', show_date],
on: {
aim_id: sequelize.literal('aim.aim_id IN(SELECT current_key FROM historysnake WHERE original_key IN(SELECT original_key FROM historysnake WHERE current_key = aim.aim_id) AND historysnake.model = "aim")')
})
...

How to build up an elasticsearch query in a better way?

I am currently using the elasticsearch helper to run queries on my elasticsearch database. Currently I am using vue.js to help build this application.
When I am paginating my results I use this query:
this.client.search({
index: 'node',
type: 'vakantie',
from: 12 * index,
size: this.size,
}).then(function (resp) {
this.travels = resp.hits.hits;
this.currentPage = index;
}.bind(this), function (err) {
console.trace(err.message);
});
I also have an input box above my results that a user can type a search term into and it will instantly filter down results using this query:
index: 'node',
type: 'vakantie',
from: 0,
size: this.size,
body: {
query: {
match_phrase_prefix: {
title: {
query: this.query,
slop: 10,
max_expansions: 50
}
}
},
highlight: {
fields: {
title: {}
},
pre_tags: ["<span class='highlight'>"],
post_tags: ["</span>"]
}
}
I have filters and sort methods in place as well, and I know how to use a query with elasticsearch to combine multiple search queries.
Obviously I don't want to write a search query for every combination of filter + input + sort possible. Is there a better way to build up my search queries than using a javascript object like this?
Hopefully I am getting my point across, I have a bit too much custom code to simply paste it here.

Meteor User table value axtracting

How do I pick the email address value from meteor Mongo user table?
I have written below query to pick the element:
users=Meteor.users.find({},{emails:1})
This the code I have written to fetch the email address, but I don't know how much it's affecting performance in the code:
users = Meteor.users.find({})
users.forEach(function(key,option){
key.emails.forEach(function (key,option){
console.log(key.address)
});
});
In meteor, you should call:
users = Meteor.users.find({}, { fields: { emails: 1 } })
Reference in docs
EDIT
Please remember users is a cursor object. Cursor objects can be handled directly in templates, and must be the return of publications. You can't iterate a cursor directly in a javascript loop.
Example: (remember authorization in production publications)
Meteor.publish('user-emails', function() {
return Meteor.users.find({}, { fields: { emails: 1 } });
});
If you want to directly access the user instances, for example to iterate them in a javascript code, you need to fetch the cursor (reference in docs).
Example:
var users = Meteor.users.find({}, { fields: { emails: 1 } }).fetch();
Now users is an array of users. Feel free to iterate them.
Example (I'm using underscore.js):
var users = Meteor.users.find({}, { fields: { emails: 1 } }).fetch();
_.each(users, function(user) {
console.log(user.emails);
});
Now, if you need a vector only with emails, one on each index, you can pluck the emails from a fetched array with underscore.js (reference of pluck)
var emails = _.pluck(Meteor.users.find({}, { fields: { emails: 1 } }).fetch(), 'emails');
Hope it works :)
if its not working, dont forget to return
return users

Publish a collections and other collection's documents which have relation with any document in the first collection

The scenario is that I want to publish one whole collection and users' data (such as profile) who have relation with any document in the the first collection.
The problem is how can I publish that part of users collections?
Well, there are two ways, first is using package
https://atmospherejs.com/cottz/publish-with-relations
And second one - in publish function you can return multiple cursors, from docs
Meteor.publish("roomAndMessages", function (roomId) {
check(roomId, String);
return [
Rooms.find({_id: roomId}, {fields: {secretInfo: 0}}),
Messages.find({roomId: roomId})
];
});
After some research, I found reywood:publish-composite solved my problem completly.
Example:
Meteor.publishComposite('getItemsList', {
find: function() {
return Items.find({});
},
children: [
{
find: function(item) {
return Meteor.users.find(
{ _id: item.userId },);
}
}
]});
This will publish all the items documents with any user document that have a relation with it. ( Items.userId is mapped to Meteor.users._id )

Categories

Resources