How to execute a dynamic number of criteria in mongoose.find? - javascript

As an example, at any given runtime,
Books = {
CatSelect : ["SciFi", "Humor", "History"],
MinPages : [300,50,500]
};
If I manually write the query in the find function as below, it works as intended and finds the books with number of pages greater than the indicated amounts in indicated categories.
MyCollection.find({ $or: [ { Category: Books.CatSelect[0], Pages : { $gte: Books.MinPages[0] } }, { Category: Books.CatSelect[1], Pages : { $gte: Books.MinPages[1] } } ] }).execFind(function(err,result){
...
}
But the problem is I would not know how many of the categories will be selected, the above example is set .find example for 2 categories.
How to put a varying number of criteria dynamically into the .find function?
Naturally I can put all the criteria in a string, but query is not a string nor a JSON, so I'm kinda lost.

You can build up your query object programmatically, based on the selections. For example:
var selections = [0, 1];
var query = { $or: [] };
for (var i=0; i<selections.length; i++) {
var selection = selections[i];
query.$or.push({
Category: Books.CatSelect[selection],
Pages: { $gte: Books.MinPages[selection] }
});
}
MyCollection.find(query).exec(function(err, result){
//...
}

Related

Sequelize [Op.and] not working with M:N association

I have two models
Units and Filters which are related with M:N association through unit_filter table
this.belongsToMany(Unit, {
through: "unit_filter",
as: "units",
});
this.belongsToMany(Filter, {
through: 'unit_filter',
as: 'filters',
});
The goal is to fetch units which have more than 1 filter associated with and condition.
let result = await Unit.findAll({
include: [
{
model: Filter,
where: {
id: {
[Op.and] : [2,252,4,80]
}
},
as: 'filters',
},
],
});
The above is only working if there is only one id in the array which does not make any sense.
Seqeulize documenation states
Post.findAll({
where: {
[Op.and]: [{ a: 5 }, { b: 6 }], // (a = 5) AND (b = 6)
}
})
So the code I have should work theoritically. I also tried with
where: {
[Op.and] : [{id:2},{id:252},{id:4},{id:80}]
}
which results in getting all the items from the db. It does not even care about the where condition in this case.
Would be of great help if any one points me in right direction.
You need to use Sequelize.literal with a subquery in where option in order to filter units that have more than 1 filter because simply indicating several ids of filters you will get units that have one of indicated filters (from 1 to N).
let result = await Unit.findAll({
where: Sequelize.where(
Sequelize.literal('(SELECT COUNT(*) FROM unit_filter as uf WHERE uf.unit_id=unit.id AND uf.filter_id in ($filter_ids))'),
Op.gt,
'1'),
bind: {
filter_ids: [2,252,4,80]
}
});

is there a method of sorting a mongoose model by the sum of 2 fields?

i have those models
[
{"trisWin":18,"trisLost":2,"pongWin":4,"_id":"6068c0c237326d13706569aa","username":"Tommaso","password":"$2a$10$2TiaY12yCcRKWleDkXCeGe1ujJf8Liv5WBzsxFjGesrZR.KtakQtW","__v":0},
{"trisWin":13,"trisLost":0,"pongWin":10,"_id":"606b838a81811a3734a9c717","username":"Test1234","password":"$2a$10$0KoOhIRzjQlsMho0rmFsLeoorTn4bjL3eGofRQuy.cc//3zIttWsa","__v":0},
{"trisWin":9,"trisLost":0,"pongWin":2,"_id":"6068ca2ad9587c2b2c8df467","username":"Giacomo","password":"$2a$10$h24RPkGssur29K1WM5aCuOVO6Uw7cY9DD.s9nOU1iEp4qb6TxSuvu","__v":0}
]
i want to sort them by the sum of "pongWin" and "trisWin"
i have tryied this const result = await User.find().sort({ trisWin: -1 })
it works, but only with the trisWin variable
You only have to add the field to the object that you pass to the sort method.
User.find().sort({ trisWin: -1, pongWin: -1 })
You cannot sort on a sum of two fields without using aggregation.
However, aggregation is quite slow and it doesn't persist the output.
What you can do is create a new field on each document as trisTotal and then sort based on that field.
If the trisWin and trisLoss``keep updating, you can also update the trisTotalin the same update query that you use for updatingtrisWinandtrisLoss```.
User.update_many(filter={}, update= {$set: {trisTotal: { $trisWin + $trisLost}}})
const result = await User.find().sort({ trisTotal: -1 })
You can use the aggregate pipeline for this
const result = await User.aggregate([
{
$addFields: { // new field to hold the total
total: {
$sum: ["$pongWin", "$trisWin"],
},
},
},
{
$sort: { // Sorting based on total
total: -1,
},
},
{
$unset: ["total"], // Removing the newly added total field after sorting
},
]);

how can i replace one value from list object and same new value assign to same object list using angularjs?

var test = list contains 10 rows with 4 columns;
test.then(function(d)){
$scope.mylist = d.data;
}
example:my list contains one row like
name:"rajesh";
id:10009;
branch:"dotnet";etc...
here i want to replace branch dotnet to angular for all rows and again that value assign same to same object.
means i need output like this?
name:"rajesh";//1st row
id:100009;
branch:"angular";
name:"sai";//2nd row
id:1004;
branch:"angular"; like this
please suggest i am new to angularjs
FYI, You are using very old JavaScript syntax. (Recommended to upgrade)
Anyways, extending the code snippet in your question.
Update
question is different from what you are asking in comments. if you are looking for code to get it done. Here it is...
const results = [
{ Name: 'raju', Id: 1009, Branch: 'cse' },
{ Name: 'sai', Id: 1019, Branch: 'ece' },
{ Name: 'nandu', Id: 1089, Branch: 'civil' }
];
const output = results.map(user => {
user.Name = '****';
return user;
});
Just use map to transform your data.
var test = list contains 10 rows with 4 columns;
test.then(function(d)){
$scope.mylist = d.data.map(function(user) {
if (user.branch === 'dotnet') {
user.branch = 'angular';
}
return user;
});
}

query an array of objects and return a single object - mongodb

I'm having some trouble searching an array I have in my model which currently contains dummy posts.
My posts array looks like this
posts: [
{
image: <filename>,
comments: [],
joined: <number>,
}
]
The posts array atm holds about 10 objects. I need a way to query this array and return a single object. I already tried the answers given on other similar questions, but they all return the whole user which is not what I want.
I tried this:
model
.find(
{ $match : { "posts.image": req.params.image } },
{ $unwind : "$posts" },
{ $match : { "posts.image": req.params.image } }
)
This also returns the whole object including the password, username, etc. I also tried $elemMatch, and no luck.
I'm only expecting it to return one object (not multiple objects) since ill be querying the array with req.params.
Unsure
Not entirely certain if this is what you are asking for, but a way to get a single property value of an array would be done this way
If I am misunderstood please clarify what you are after and I will amend my answer.
var posts = [{
image: "x.jpg",
comments: [],
joined: 12
},
{
image: "x1.jpg",
comments: [],
joined: 121
},
{
image: "ax.jpg",
comments: [],
joined: 2
}
];
for (a = 0; a < posts.length; a++){
console.log(posts[a].image);
}

Filter to not Include Matched Values in Result Arrays

I have a query where I first want to match find the list of matched users and then filter the matches out from the array of external users that was passed in so that I am left with users Id's that have not been matched yet.
Here is a the match Schema:
const mongoose = require('mongoose'); // only match two users at a time.
const Schema = mongoose.Schema;
const MatchSchema = new Schema({
participants: [{
type: String, ref: 'user'
}],
blocked: {
type: Boolean,
default: false
}
});
Here is the query with explanations:
db.getCollection('match').aggregate([
{
'$match': {
'$and': [
{ participants: "599f14855e9fcf95d0fe11a7" }, // the current user.
{ participants: {'$in': [ "598461fcda5afa9e0d2a8a64","598461fcda5afa9e0d111111", "599f14855e9fcf95d0fe5555"] } } // array of external users that I want to check if the current user is matched with.
]
}
},
{
'$project': {
'participants': 1
}
},
This returns the following result:
{
"_id" : ObjectId("59c0d76e66dd407f5efe7112"),
"participants" : [
"599f14855e9fcf95d0fe11a7",
"599f14855e9fcf95d0fe5555"
]
},
{
"_id" : ObjectId("59c0d76e66dd407f5efe75ac"),
"participants" : [
"598461fcda5afa9e0d2a8a64",
"599f14855e9fcf95d0fe11a7"
]
}
what I want to do next it merge the participants array form both results into one array.
Then I want to take away the those matching items from the array of external users so that I am left with user id's that have not been matched yet.
Any help would be much appreciated!
If you don't want those results in the array, then $filter them out.
Either by building the conditions with $or ( aggregation logical version ):
var currentUser = "599f14855e9fcf95d0fe11a7",
matchingUsers = [
"598461fcda5afa9e0d2a8a64",
"598461fcda5afa9e0d111111",
"599f14855e9fcf95d0fe5555"
],
combined = [currentUser, ...matchingUsers];
db.getCollection('match').aggregate([
{ '$match': {
'participants': { '$eq': currentUser, '$in': matchingUsers }
}},
{ '$project': {
'participants': {
'$filter': {
'input': '$participants',
'as': 'p',
'cond': {
'$not': {
'$or': combined.map(c =>({ '$eq': [ c, '$$p' ] }))
}
}
}
}
}}
])
Or use $in ( again the aggregation version ) if you have MongoDB 3.4 which supports it:
db.getCollection('match').aggregate([
{ '$match': {
'participants': { '$eq': currentUser, '$in': matchingUsers }
}},
{ '$project': {
'participants': {
'$filter': {
'input': '$participants',
'as': 'p',
'cond': {
'$not': {
'$in': ['$p', combined ]
}
}
}
}
}}
])
It really does not matter. It's just the difference of using JavaScript to build the expression before the pipeline is sent or letting a supported pipeline operator do the array comparison where it is actually supported.
Note you can also write the $match a bit more efficiently by using an "implicit" form of $and, as is shown.
Also note you have a problem in your schema definition ( but not related to this particular query ). You cannot use a "ref" to another collection as String in one collection where it is going to be ObjectId ( the default for _id, and presumed of the hex values obtained ) in the other. This mismatch means .populate() or $lookup functions cannot work. So you really should correct the types.
Unrelated to this. But something you need to fix as a priority.

Categories

Resources