Let's say I have a schema with an index of:
Person.index({ name: 'text', occupation: 'text', country: 'text' })
and a collection of Person documents such as:
[
{
name: 'John Doe',
occupation: 'Doctor',
country: 'Canada'
},
{
name: 'Mary Smith',
occupation: 'Doctor',
country: 'Brazil'
}
]
When I query with a search term like the following:
PersonModel.find(
{ $text: { $search: 'Mary Doctor Canada' } },
{ score: { $meta: 'textScore' } }
).sort(
{ score: { $meta: 'textScore' } }
)
How can I ensure that the first word in the search term has a higher importance than that of the following? In this instance, how can I make it that "Mary" is received a higher text score than "Canada" in the search term?
Similarly, if the search term was instead "Brazil John", then how can I make sure that Mary receives the higher text score, since the term "Brazil" comes before "John"?
Related
Schema:
const restaurantSchema = new mongoose.Schema({
address: {
building: String,
coord: [Number, Number],
street: String,
zipcode: String,
},
borough: String,
cuisine: String,
grades: [{ date: Date, grade: String, score: Number }],
name: String,
restaurant_id: String,
});
I am trying to find a restaurant with the highest grades.score and return what that score is.
What I've tried doing:
Restaurant.find({}, { "grades.score": 1, _id: 0 }).sort({ "grades.score": -1 }).limit(1).exec((err, docs) => {
if (err) {
console.log(err);
} else {
console.log(docs);
}
});
What it returns:
[
{
grades: [ [Object], [Object], [Object], [Object], [Object], [Object] ]
}
]
What I want:
[
{
score: 131
}
]
Query
you can use the $max aggregate operator that works as accumulator and on arrays like here
this is for the local(inside the document array) max-score if you want for the global(in all the collection) you can sort desc by max-score
and $limit 1
Playmongo
aggregate(
[{"$project": {"_id": 0, "max-score": {"$max": "$grades.score"}}}])
I've worked on this for about an hour now and I can't figure anything out that works so sorry if this is obvious.
I want my query to only return results where every result matches, but right now it returns a result if at least one match is found.
My document looks like this...
{
country: 'Great Britain',
data: [
{
school: 'King Alberts',
staff: [
{
name: 'John',
age: 37,
position: 'Head Teacher'
},
{
name: 'Grace',
age: 63,
position: 'Retired'
},
{
name: 'Bob',
age: 25,
position: 'Receptionist'
}
]
},
{
school: 'St Johns',
staff: [
{
name: 'Alex',
age: 22,
position: 'Head of Drama'
},
{
name: 'Grace',
age: 51,
position: 'English Teacher'
},
{
name: 'Jack',
age: 33,
position: 'Receptionist'
}
]
},
// ... more schools
]
}
The query I'm currently making looks like...
{ 'data.staff.name': { $in: names } }
and the 'names' array that is being provided looks like ['Bob', 'Grace', 'John', 'Will', 'Tom']. Currently both schools are being returned when I make this query, I think it's because the 'names' array contains 'Grace' which is a name present at both schools and so the document it matching. Does anyone know if there's a query I could make so mongodb only returns the school object if every name in the 'names' array is a member of staff at the school?
You need to use the aggregation pipeline for this, after matching the document we'll just filter out the none matching arrays, like so:
db.collection.aggregate([
{
$match: {
"data.staff.name": {
$in: names
}
}
},
{
$addFields: {
data: {
$filter: {
input: "$data",
cond: {
$eq: [
{
$size: {
"$setIntersection": [
"$$this.staff.name",
names
]
}
},
{
$size: "$$this.staff"
}
]
}
}
}
}
}
])
Mongo Playground
I'm trying to implement a user search that looks into the user's given names and their username, while also being able to sort results by relevance.
I tried creating a text index like this
db.users.createIndex({
username: 'text',
firstName: 'text',
lastName: 'text'
},
{
name: 'text_search',
default_language: 'en',
language_override: 'language'
})
But this doesn't take into account partial terms, so if I search for "Juan F", I get the following results
{ score: 3.7, username: "juanjo", firstName: "Juan", lastName: "Rivas F" },
{ score: 2.95, username: "Juan.rodriguez", firstName: "Juan", lastName: "Rodriguez" },
{...} // 6 more
{ score: 2.2, lastName: "Fuentes", firstName: "Juan", username: "juanfuentes" }
I understand that text indexes take into account similar words, but not partial terms, so with "Juan Fuente" I get the desired result, with "Juan F", "Juan Fu", etc, I don't.
Is there a way to improve this, in order to be able to implement a search that returns results as the user types into a search box?
Edit This is the query I tried:
db.users.find(
{ $text: { $search: "juan f" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })
I have two tables users (fields: name, age) and links (fields: title, url, userId(ref to users)). There is a one-to-many relation between users to links. Now I want to run a query like : select * from links where user has age more than 26.
I have been trying with query like :
Links
.find({title:'Chemistry'})
.populate({
path: 'userId',
select: 'name.first age -_id',
match: {age: {$gte: 26}}
})
.exec( function(err,data) {
if (err) console.log( err );
console.log( 'data', data);
res.jsonp(data);
});
This gives me the following result :
[
{
_id: "54037d00e74f00f917e709ff",
title: "Chemistry",
url: "http://chemistry.com",
comment: "Great chemo slides",
favourites: "507",
userId: {
name: {
first: "Bob"
},
age: 31
},
tags: [
"tutorials",
"chemo"
]
},
{
_id: "540457f2557cded82b331ee2",
title: "Chemistry",
url: "http://chemistry.com",
comment: "Great chemo slides",
favourites: "507",
userId: null,
tags: [
"tutorials",
"chemo"
]
}
]
Notice that the userId is null in the second object. I am not sure my query is right, but I think it should be a simple enough query for mongodb to support it. I probably don't know how to do it, do you have any idea about this ? Thanks.
I have MongoDB documents structured like this:
{_id: ObjectId("53d760721423030c7e14266f"),
fruit: 'apple',
vitamins: [
{
_id: 1,
name: 'B7',
usefulness: 'useful',
state: 'free',
}
{
_id: 2,
name: 'A1',
usefulness: 'useful',
state: 'free',
}
{
_id: 3,
name: 'A1',
usefulness: 'useful',
state: 'non_free',
}
]
}
{_id: ObjectId("53d760721423030c7e142670"),
fruit: 'grape',
vitamins: [
{
_id: 4,
name: 'B6',
usefulness: 'useful',
state: 'free',
}
{
_id: 5,
name: 'A1',
usefulness: 'useful',
state: 'non_free',
}
{
_id: 6,
name: 'Q5',
usefulness: 'non_useful',
state: 'non_free',
}
]
}
I want to query and get all the fruits which have both {name: 'A1', state: 'non_free'} and {name: 'B7', state: 'free'}.
In the worst case I want at least to count these entries if getting them is not possible and if the equivalent code exists for pymongo, to know how to write it.
For the given example I want to retrieve only the apple (first) document.
If I use $elemMatch it works only for one condition, but not for both. E.g. if I query find({'vitamins': {'$elemMatch': {'name': 'A1', 'state': 'non_free'}, '$elemMatch': {'name': 'B7', 'state': 'free'}}}) it will retrieve all the fruits with {'name': 'B7', 'state': 'free'}.
In this case you can use the $and-operator .
Try this query:
find({
$and: [
{'vitamins': {'$elemMatch': {'name': 'A1', 'state': 'non_free'} } },
{'vitamins': {'$elemMatch': {'name': 'B7', 'state': 'free'} } }
]
});
To explain why you received only the result matching the second criteria: The objects inside each {} you pass to MongoDB are key/value pairs. Each key can only exist once per object. When you try to assign a value to the same key twice, the second assignment will override the first. In your case you assigned two different values to the key $elemMatch in the same object, so the first one was ignored. The query which actually arrived in MongoDB was just find({'vitamins': {'$elemMatch': {'name': 'B7', 'state': 'free'}}}).
Whenever you need to apply the same operator to the same key twice, you need to use $or or $and.
var fruits = db.fruits.find({
"vitamins": {
$all: [{
$elemMatch: {
"name": "A1",
"state": "non_free"
}
}, {
$elemMatch: {
"name": "B7",
"state": "free"
}
}]
}
})
let query = [];
query.push({
id: product.id,
});
query.push({ date });
for (const slot of slots) {
query.push({
slots: {
$elemMatch: {
id: slot.id,
spots: { $gte: slot.spots },
},
},
});
}
const cal = await Product.findOne({ $and: query });