I have a document that looks like:
{
_id: "....",
hostname: "mysite.com",
text: [
{
source: "this is text. this is some pattern",
...
},
{
source: "....",
...
}
]
}
and I am trying to delete the items from the text array which match a specific condition in my query given as:
db.getCollection('TM').updateMany(
{hostname: "mysite.com"},
{
$pull: {
"text.source": /this is some pattern/
}
},
{ multi: true }
)
Here I want to delete all the items from the array where the value inside source matches this is some pattern. When I execute this query, it gives an error saying: Cannot use the part (source) of (text.source) to traverse the element with error code 28.
What is the way to achieve this?
it gives an error saying: Cannot use the part (source) of (text.source) to traverse the element with error code 28.
Incorrect syntax of $pull for update methods,
Corrected syntax, and You can use $regex to find document by specific pattern,
"text.source" the condition in filter part will filter main documents, it is optional
text: { source: will filter sub documents and pull elements
db.getCollection('TM').updateMany(
{
hostname: "mysite.com",
"text.source": { $regex: "this is some pattern" }
},
{
$pull: {
text: { source: { $regex: "this is some pattern" } }
}
}
)
Playground
Related
I want to implement a simple search query using Elasticsearch.
I have two fields, "title" and "description" that I would like to match the searched term with. Currently, I have the body shown below as the body for search body. How can I make it so that the search prioritizes the title match, but if there are matches in the description, they are still included in the search (with lower priority)? Thanks in advance.
body = {
size: 200,
from: 0,
query: {
prefix: {
title: searchTerm
}
}
}
You have to use a constant score query with a score of 0 for the "other" field. Any other boost / function score usage will not reliably score a certain field over another field as the scoring is based on other parameters like text length for example, this means a constant boost (unless very very large) can not guarantee the behaviour you seek.
By using a constant score for each field you can control score manually, like so:
{
size: 200,
from: 0,
query: {
bool: {
should: [
{
prefix: {
title: searchTerm
}
},
{
constant_score: {
filter: {
prefix: {
description: searchTerm
}
},
boost: 0
}
},
]
}
}
}
If you set description boost to be more than 0 then the score will be the combined score of both fields, by doing this you can prioritize documents that have that prefix in both fields over ones that have it in just the title field.
You can use a combination of bool/should clause along with the boost parameter
{
"query": {
"bool": {
"should": [
{
"prefix": {
"title": {
"value": "searchterm"
}
}
},
{
"prefix": {
"description": {
"value": "searchterm",
"boost": 4
}
}
}
]
}
}
}
I am trying to make call from my angular service to loopback api. I have a parcelStatuses collection that contains a parcelId so i am able to include parcel collection too but I also need to check against a particular vendorId and that vendorId exists in parcel collection. I am trying to make use of scope to check against particular vendorId but i think i am not writing correct json syntax/call. Here is my function inside service
private getParcelsByFilter(
limit: number,
skip: number,
vendorId: string,
filter: string
) {
const checkFilter = {
"where": {
"and": [{"statusRepositoryId": filter}]
},
"include": [
{
"parcel": [
{
"scope": {"vendorId": vendorId}
},
"parcelStatuses",
{"customerData":"customer"}
]
}
],
"limit": limit,
"skip": skip,
}
return this._http.get<IParcel[]>(
`${environment.url}/ParcelStatuses?filter=${encodeURIComponent(JSON.stringify(checkFilter))}`
);
}
Here is my demo view of parcelStatus collection object
[{
"id":"lbh24214",
"statusRepositoryId":"3214fsad",
"parcelId":"LH21421"
}]
Demo json of parcel
[{
"id":"LHE21421",
"customerDataId":"214fdsas",
"customerId":"412dsf",
"vendorId":"123421"
}]
Please help me with writing correct call
Formatting aside, there's several issues with the query:
Unnecessary and
This line:
where: {
and: [{statusRepositoryId: filter}]
}
Can be simplified to:
where: {
statusRepositoryId: filter
}
As there is only 1 where condition, and becomes redundant.
Misuse of include and scope
include is used to include relations while scope applies filters to those relations. They can work in tandem to create a comprehensive query:
include: [
{
relation: "parcels",
scope: {
where: {vendorId: vendorId},
}
}
],
This will include the parcels relation as part of the response, while filtering the parcels relation with a where filter.
That means the final code should look similar to the following:
private getParcelsByFilter(
limit: number,
skip: number,
vendorId: string,
filter: string
) {
const checkFilter = {
where: {statusRepositoryId: filter},
include: [
{
relation: "parcels",
scope: {
where: {vendorId: vendorId},
}
}
],
limit: limit,
skip: skip,
}
return this._http.get<IParcel[]>(
`${environment.url}/ParcelStatuses?filter=${encodeURIComponent(JSON.stringify(checkFilter))}`
);
}
Further reading
Please review these resources to get a better understanding on how to use filters.
https://loopback.io/doc/en/lb4/Include-filter.html
I have a mongoose model in which some fields are like :
var AssociateSchema = new Schema({
personalInformation: {
familyName: { type: String },
givenName: { type: String }
}
})
I want to perform a '$regex' on the concatenation of familyName and givenName (something like 'familyName + " " + 'givenName'), for this purpose I'm using aggregate framework with $concat inside $project to produce a 'fullName' field and then '$regex' inside $match to search on that field. The code in mongoose for my query is:
Associate.aggregate([
{ $project: {fullName: { $concat: [
'personalInformation.givenName','personalInformation.familyName']}}},
$match: { fullName: { 'active': true, $regex: param, $options: 'i' } }}
])
But it's giving me error:
MongoError: $concat only supports strings, not double on the first
stage of my aggregate pipeline i.e $project stage.
Can anyone point out what I'm doing wrong ?
I also got this error and then discovered that indeed one of the documents in the collection was to blame. They way I fished it out was by filtering by field type as explained in the docs:
db.addressBook.find( { "zipCode" : { $type : "double" } } )
I found the field had the value NaN, which to my eyes wouldn't be a number, but mongodb interprets it as such.
Looking at your code, I'm not sure why $concat isn't working for you unless you've had some integers sneak into some of your document fields. Have you tried having a $-sign in front of your concatenated values? as in, '$personalInformation.givenName'? Are you sure every single familyName and givenName is a string, not a double, in your collection? All it takes is one double for your $concat to fold.
In any case, I had a similar type mismatch problem with actual doubles. $concat indeed supports only strings, and usually, all you'd do is cast any non-strings to strings.. but alas, at the time of this writing MongoDB 3.6.2 does not yet support integer/double => string casting, only date => string casting. Sad face.
That said, try adding this projection hack at the top of your query. This worked for me as a typecast. Just make sure you provide a long enough byte length (128-byte name is pretty long so you should be okay).
{
$project: {
castedGivenName: {
$substrBytes: [ 'personalInformation.givenName', 0, 128 ]
},
castedFamilyName: {
$substrBytes: [ 'personalInformation.familyName', 0, 128 ]
}
},
{
$project: {
fullName: {
$concat: [
'$castedGivenName',
'$castedFamilyName'
]
}
}
},
{
$match: { fullName: { 'active': true, $regex: param, $options: 'i' } }
}
I managed to make it work by using $substr method, so the $project part of my aggregate pipeline is now:
`$project: {
fullName: {
$concat: [
{ $substr: ['$personalInformation.givenName', 0, -1] }, ' ', { $substr: ['$personalInformation.familyName', 0, -1] }
]
}
}
}`
{
TypeList" : [
{
"TypeName" : "Carrier"
},
{
"TypeName" : "Not a Channel Member"
},
{
"TypeName" : "Service Provider"
}
]
}
Question :
db.supplies.find("text", {search:"\"chann\" \"mem\""})
For above query I want display :
{
TypeName" : "Not a Channel Member"
}
But I am unable to get my result.
What are changes I have to do in query .
Please help me.
The below query will return your desired result.
db.supplies.aggregate([
{$unwind:"$TypeList"},
{$match:{"TypeList.TypeName":{$regex:/.*chann.*mem.*/,$options:"i"}}},
{$project:{_id:0, TypeName:"$TypeList.TypeName"}}
])
If you can accept to get an output like this:
{
"TypeList" : [
{
"TypeName" : "Not a Channel Member"
}
]
}
then you can get around using the aggregation framework which generally helps performance by running the following query:
db.supplies.find(
{
"TypeList.TypeName": /chann.*mem/i
},
{ // project the list in the following way
"_id": 0, // do not include the "_id" field in the output
"TypeList": { // only include the items from the TypeList array...
$elemMatch: { //... where
"TypeName": /chann.*mem/i // the "TypeName" field matches the regular expression
}
}
})
Also see this link: Retrieve only the queried element in an object array in MongoDB collection
i have a Mongodb collection named "EVENTS" and in the collection i have an object of array which looks like this:
{
"Events":[
{
"_id":"53ae59883d0e63aa77f7b5b2",
"Title":"Title Blank",
"Desc":"Description Blank",
"Date":"2014-06-04 00:30",
"Link":"http://googleparty.com",
"Event":"Victoria Centre",
"dateCreated":"28/6/2014 06:58"
},
{
"_id":"53ae59883d0e63aa77f7b5b3",
"Title":"Hello World",
"Desc":"hello",
"Date":"2014-06-04 00:30",
"Link":"http://linkedinparty.com",
"Event":"social",
"dateCreated":"30/2/2014 11:10"
}
]
}
how would i delete an object by id in node.js so " delete(53ae59883d0e63aa77f7b5b2)" will yield this:
{
"Events":[
{
"_id":"53ae59883d0e63aa77f7b5b3",
"Title":"Hello World",
"Desc":"hello",
"Date":"2014-06-04 00:30",
"Link":"http://linkedinparty.com",
"Event":"social",
"dateCreated":"30/2/2014 11:10"
}
]
}
Regards
If all you really want to do is "empty" the array then you just need to use the $set operator with an .update() and "set" the array as an empty one:
db.collection.update({},{ "$set": { "Events": [] } },{ "mutli": true})
So the .update() operation takes a "query" to select the documents in your collection, a blank query as shown selects everything. The "update" section contains the $set operation that just replaces the current "Events" field with an empty array.
The "multi" option there makes sure this is applied to every document that matches. The default is false and will only update the first document that matches.
For more specific operations removing selected array elements, look at the $pull operator. Your edit shows now that this is what you want to do:
db.collection.update(
{ "Events._id": ObjectId("53ae59883d0e63aa77f7b5b2") },
{ "$pull": { "Events": { "_id": ObjectId("53ae59883d0e63aa77f7b5b2") } } }
)
But your inclusion of arrays with _id fields seems to indicate that you are using mongoose, so the ObjectId values are cast automatically:
Model.update(
{ "Events._id": "53ae59883d0e63aa77f7b5b2" },
{ "$pull": { "Events": { "_id": "53ae59883d0e63aa77f7b5b2" } } },
function(err,numAffected) {
}
);