How to filter minimongo collection with more parameters in meteor - mongodb

I need help with filtering reactively minimongo collection with 3+ parameters. Firs, I have loaded minimongo from server's mongo collection with publish/subscribe. Now, I want to filter that collection and let user see only objects from collection that are same like filters. First of all I have search query filter that checks if input string is same as some filed in collection:
Job.find({ $or: [ { Name: regex }, { Description: regex }, ]});
This part is doing his job well. And now second filter: I have field in object that is true if that particular job is remote friendly and false if it is not, I wanted to if user enables that filter he only see just remote friendly job positions, and if he disables that, he can see all jobs available ( + search query of course):
if (remoteQuery === true ) {
return Job.find({ $or: [ { Name: regex }, { Description: regex }, ] , Remote: true});
}
This is working, but it is bad way for doing this. And now biggest problem comes with last filter: I have one more field that is storing "job" (collection object) type. Type can be 1, 2 , 3 or 4. So how could I say to minimongo e.g. "Show only jobs that have "Front-end" inside (search query), that are remote friendly, and have third filter 2 and 3 inside"
Job.find({ $or: [ { Name: "Front-end"}, { Description: "Front-end"}, ] , Remote: true, positionType: [2,3],});
Something like this? Thanks!

Sounds like you are looking for the MongoDB query $in operator:
The $in operator selects the documents where the value of a field equals any value in the specified array.
Therefore your 3rd query could look like:
Job.find({
positionType: {
$in: [2, 3] // Matches documents where `positionType` is either 2 or 3
},
// Other conditions…
});

Related

what is the proper way to use $nin operator with mongoDB

I want to find entries in my MongoDB collection that match some filters.
Each entry in my mongo collection looks like this data:
{
type: "admin"
senderId: "6131e7c597f50700160703fe"
read_by: [
{
Object_id: 614dbbf83ad51412f16c0757
readerId: "60b968dc5150a20015d6fcae"
}
]
},
{
type: "admin"
senderId: "6131e7c597f50700160703fe"
read_by: [
{}
]
}
What I want to achieve properly, is to filter on the collection and get only the entries that match 'admin' as type and that don't have the current user's ID in the read_by array (that is an array of objects)
I wrote this (and tried some other combinations with errors :) )
but it is not working, I get 0 entries on the end, but I expect to get one of the two as the second have it's read_by array empty.
Thank you very much!
I validated my solution using cloud.mongodb.com interface and the simplest following filter seems to do the job:
{ "read_by.readerId": {$ne:"60b968dc5150a20015d6fcae"}}
Only the record with empty array is being returned.
$nin operator works fine as well but if there is only single value for comparision then $ne should be enough.
{ "read_by.readerId": {$nin: ["60b968dc5150a20015d6fcae"]}}

Query Mongoose with priority query conditions

I need to find all documents where first query argument matches then if it can't find more documents that match that query it should apply another query argument.
so for example:
db.users.find({
$or: [
{ type: typeToSearch }, // First find all users that has type=typeToSearch
{ active: true } // then if it can't find more users with type=typeToSearch then look for active one
]})
.limit(20)
What actually this query does it will find active users first (depending on the order in a collection).
What I need is - if I have 18 users that have given type then they should be returned first and then 2 any active.
That's a cool feature you are looking for! Nothing in Mongoose will help you with this out of the box, and poking around in npm I don't see anything that will help you there either.
For your two queries you have to do something like this:
const fancyQuery = async limit => {
const first = await db.users.find({ type: typeToSearch }).limit(20)
let second = [];
if (first.length < limit)
second = await db.users.find({ active: true,
type:{$ne:typeToSearch}} })
.limit(20-first.length)
return [...first, ...second]
}
The only other path I can think of using the query api, is to fetch 40 items and then to filter the results with javascript. I think you'd need to change your query a little to prevent the active = true part of the query from also refetching all the same documents as the type query:
db.users.find({
$or: [
{ type: typeToSearch },
{ active: true,
type: {$ne: typeToSearch}
}
]})
.limit(40)
You'd filter the results first by type and then by not type and active up to 20 items.
You might also be able to use an aggregation pipeline to accomplish this, but I don't have an answer like that at my finger-tips.

Select the last document from mongo collection in meteor

I want the latest document in the query. Below I'm getting those documents whose name is coming from the variable 'personalFullName, then sorting them by a field called 'RecordID' (this field has higher numbers as later date entries), then grab the last one. I want the latest (the one with the largest RecordID number) entry in this query:
Programs.find({ FullName: personalFullName }, { sort: { RecordID: 1 }, limit: 1}).fetch().pop();
I'm getting an error that it's exceeding the call stack size.
If you are comfortable using the meteorhacks:aggregate package then you could always publish the item(s) you want using the mongo aggregate pipeline, perhaps something like this (code is coffeescript):
Meteor.publish 'latestPrograms', (personalFullName)->
return unless personalFullName?
check personalFullName, String
pipeline = [
{$match:{'Fullname': personalFullName}}
{$sort: {'RecordID': 1}}
{$group:{'_id':{Fullname: '$Fullname'}, RecordID:{$last:'$RecordID'}}}
{$limit:1}
]
#added 'latestPrograms', Random.id(), item for item in programs.aggregate pipeline
#ready()
You can then grab the data by subscribing to the latestPrograms pseudo collection. Here is an example using a iron router route:
Router.route '/home',
name: 'home'
template:'homepage'
waitOn:->
Meteor.subscribe 'latestPrograms', personalFullName
data:->
{latestPrograms: latestPrograms.find()}

MongoDB update fields of subarrays that meet criteria

I am having a problem where I need to update a specific field found in arrays contained in a bigger array that match certain criteria as of MongoDB v2.2.3.
I have the following mongodb sample document.
{
_id: ObjectId("50be30b64983e5100a000009"),
user_id: 0
occupied: {
Greece: [
{
user_id: 3,
deadline: ISODate("2013-02-08T19:19:28Z"),
fulfilled: false
},
{
user_id: 4,
deadline: ISODate("2013-02-16T19:19:28Z"),
fulfilled: false
}
],
Italy: [
{
user_id: 2,
deadline: ISODate("2013-02-15T19:19:28Z"),
fulfilled: false
}
]
}
}
Each country in the occupied array has its own set of arrays.
What I am trying to do is find the document where user_id is 0, search through the occupied.Greece array only for elements that have "deadline": {$gt: ISODate(current-date)} and change their individual "fulfilled" fields to true.
I have tried the $ and $elemMatch operators but they match only one, the first, array element in a query whereas I need it to match all eligible elements by the given criteria and make the update without running the same query multiple times or having to process the arrays client-side.
Is there no server-side solution for generic updates in a single document? I am developing using PHP though a solution to this should be universal.
I'm afraid this is not possible. From the documentation:
Remember that the positional $ operator acts as a placeholder for the first match of the update query selector. [emphasis not mine]
This is tracked in the MongoDB Jira under SERVER-1243.
There's quite a number of related feature requests in the jira, mostly under the topic 'virtual collections'.

mongodb mapreduce function does not provide skip functionality, is their any solution to this?

Mongodb mapreduce function does not provide any way to skip record from database like find function. It has functionality of query, sort & limit options. But I want to skip some records from the database, and I am not getting any way to it. please provide solutions.
Thanks in advance.
Ideally a well-structured map-reduce query would allow you to skip particular documents in your collection.
Alternatively, as Sergio points out, you can simply not emit particular documents in map(). Using scope to define a global counter variable is one way to restrict emit to a specified range of documents. As an example, to skip the first 20 docs that are sorted by ObjectID (and thus, sorted by insertion time):
db.collection_name.mapReduce(map, reduce, {out: example_output, sort: {id:-1}, scope: "var counter=0")};
Map function:
function(){
counter ++;
if (counter > 20){
emit(key, value);
}
}
I'm not sure since which version this feature is available, but certainly in MongoDB 2.6 the mapReduce() function provides query parameter:
query : document
Optional. Specifies the selection criteria using query operators for determining the documents input to the map
function.
Example
Consider the following map-reduce operations on a collection orders that contains documents of the following prototype:
{
_id: ObjectId("50a8240b927d5d8b5891743c"),
cust_id: "abc123",
ord_date: new Date("Oct 04, 2012"),
status: 'A',
price: 25,
items: [ { sku: "mmm", qty: 5, price: 2.5 },
{ sku: "nnn", qty: 5, price: 2.5 } ]
}
Perform the map-reduce operation on the orders collection using the mapFunction2, reduceFunction2, and finalizeFunction2 functions.
db.orders.mapReduce( mapFunction2,
reduceFunction2,
{
out: { merge: "map_reduce_example" },
query: { ord_date:
{ $gt: new Date('01/01/2012') }
},
finalize: finalizeFunction2
}
)
This operation uses the query field to select only those documents with ord_date greater than new Date(01/01/2012). Then it output the results to a collection map_reduce_example. If the map_reduce_example collection already exists, the operation will merge the existing contents with the results of this map-reduce operation.