I am trying to do a text search of the collection called DAFacility in MongoDB Compass:
_id:62170597b3fa8994a0d9a0c8
author:"User"
organizationName:"TSTT"
eventName:"Facility Assessment After Disaster"
eventDate:2022-02-01T00:00:00.000+00:00
area:"Siparia"
disasterNature:"Earthquake"
threatLevel:"High"
surroundingDamage:"Cracked Foundations and Roads"
facilityName:"Point Lisas Main Facility"
facLocation:Array
facStatus:"Operable"
operEqu:23
inoperEqu:7
facilityDamage:"Cracked Walls and Floors"
facImage:Array
__v:0
I am trying to search the field facilityDamage where i can search maybe one word from the entire data entry (eg searching the word "Walls" and having the entire entry shows up)
I am trying to perform it within mongoDB data aggregation option with the template being:
[
{
'$search': {
'index': 'string',
'text': {
'query': 'string',
'path': 'string'
}
}
}
]
I have read the document which got me more confused as to what goes in the index, query and path.
can you all advise me as to what variables goes into index, query and path.
Whenever i use it within node it returns an empty array:
exports.DAEquipment_damage_search = (req, res) => {
DAEquipment.aggregate([
[
{
'$match': {
'$or': [
{'facilityDamage':{ '$regex':'.*' + req.body.facilityDamage + '.*','$options': 'i' } }
]
}
}
}
]
]).then((DAEquipment) => {
res.send(DAEquipment);
console.log(DAEquipment);
})
.catch((e) => {
res.send(e);
});
};
await DAFacility.aggregate([
{
$match: {
$or: [
{"facilityDamage":{ $regex:'.*' + searchText + '.*',$options: 'i' } },
]
}
},
])
May it will help you
Related
I am trying to implement a search feature to MongoDB and this is the aggregate pipeline I am using:
[
{
'$search': {
'text': {
'query': 'albus',
'path': [
'first_name', 'email', 'last_name'
]
}
}
}, {
'$project': {
'_id': 1,
'first_name': 1,
'last_name': 1
}
}, {
'$limit': 5
}
]
The command returns documents that contain only exactly albus or Albus, but return nothing for queries like alb, albu, etc. In the demo video I watched here: https://www.youtube.com/watch?time_continue=8&v=kZ77X67GUfk, the instructor was able to search based on substring.
The search index I am currently using is the default dynamic one.
How would I need to change my command?
You need to use the autocomplete feature, so your query will look like this:
{
$search: {
"autocomplete": {
'query': 'albus',
'path': [
'first_name', 'email', 'last_name'
]
}
}
}
Mind you both first_name, email and last_name need to be mapped as autocomplete type so a name like albus will be indexed as a, al, alb, albu, albus. Obviously this will vastly increase your index size.
Another thing to consider is tweaking the maxGrams and tokenization parameters. this will allow very long names to still work as expected and if you want to allow substring match like lbu matching albus.
I have a document of this kind:
{
_id: "123",
arrayName: [
{ text: 'first', field: false},
{ text: 'second', field: true},
{ text: 'third', field: false}
]
}
Now I would like to my query to return the length of filtered arrayName to have only the objects where field === false.
I have tried many queries with db.collection.find({}) but I always receive the entire document and in the end and it count() => to 1.
Any suggestion?
thanks
You can use projection operator to achieve what you want.
Try this:
db.collection.find({
_id : givenId ,
"arrayName.field" : false
},{
"arrayName.$":1
},function(err,result){
if(!err){
len = result.arrayName.length;
//use len however you want.
}
});
"arrayName.$":1 will select only the matched elements of the array. Then you can get the length of array with field:false
Hope this helps!
Another user already give you the right answer for your question using the plain Mongo query. But I think it won't have much because you are using Mongo with Meteor, so here I present you another way to solve your problem by using transform function in find command:
Collection.find({
// ...
}, {
transform(doc) {
doc.filterArrayLength = doc.arrayName.filter(obj => obj.field === false).length;
return doc;
}
}).fetch();
With this command the result will be like:
[
// ...
{
_id: "123",
arrayName: [
{
text: 'first',
field: false
}, {
text: 'second',
field: true
}, {
text: 'third',
field: false
}
],
filterArrayLength: 2
}
]
In Mongoose, lets say I have a User object pulled from MongoDB and that user has an array of Interests. Now I get an instance of one of that user's Interests.
var user = ...
var interest = ...
... //Make some changes to interest.
How do I update that Interest object (after making some changes to it) within the User array in the DB?
Edit
Here is my current code. It doesn't work and doesn't give an error.
User.update(
{
'_id': user._id,
'interests._id': interest._id
},
{
'$set': {
'interests.$.xyzProperty': interest.xyzProperty
}
},
function(err,obj){//some error checking}
);
If you set an if for each interest, you can access the interest by the $ operator.
user document
{
_id: ObectId('54b568531ef35a7c348f21f2'),
interests: [
{
_id: 12345,
title: 'Tacos',
description: 'I Love tacos'
},
{...},
{...},
]
}
If I know which interest sub document I want to update, I simply query it like so:
UserModel.find({_id: ObectId('54b568531ef35a7c348f21f2'), 'interests.i_d': 12345}).lean().exec(function (err, user) {
var interest = ... //find specific interest
interest.description = 'I love tacos... Like, a lot'.
UserModel.update(
{
_id: user._id,
'interests._id': interest._id
},
{
$set: {
'interests.$.description': interest.description
}
},
function (err, update) {
console.log(err, update);
}
);
});
This uses the $ positional operator and updates the specific sub document(or item in an array).
I have items like these in my collection
{
user: data,
somestuff: [somedata ...],
terminals: [ {
label: data,
details: [{more content}, {}, ...]
}]
}
I would use 'find' to extract "details" field for a specific terminal 'label'
I know that there is an easy way to get the "terminals" array by:
collection.find({_id: "..."}, {_id:0, terminals: 1})
Wich return
{ terminals: [ {
label: data,
details: [{more content}, {}, ...]
}]
}
I tried
collection.find({ "terminals.label": data }, { _id: 0, "terminals.$.details": 1 })
As edirican has suggested
And it almost work, but it return the same structure than previously except that the terminals list contain only the labeled document
The result I expect is the details list, extracted from terminals
{ details: [{more content}, {}, ...] }
Thanks for your help !
Use positional ($) projection.
http://docs.mongodb.org/manual/reference/operator/projection/positional/
collection.find({ "terminals.label": 2 }, { _id: 0, "terminals.$.details": 1 })
Assuming I have a collection in MongoDB with 5000 records, each containing something similar to:
{
"occupation":"Doctor",
"name": {
"first":"Jimmy",
"additional":"Smith"
}
Is there an easy way to rename the field "additional" to "last" in all documents? I saw the $rename operator in the documentation but I'm not really clear on how to specify a subfield.
You can use:
db.foo.update({}, {
$rename: {
"name.additional": "name.last"
}
}, false, true);
Or to just update the docs which contain the property:
db.foo.update({
"name.additional": {
$exists: true
}
}, {
$rename: {
"name.additional": "name.last"
}
}, false, true);
The false, true in the method above are: { upsert:false, multi:true }. You need the multi:true to update all your records.
Or you can use the former way:
remap = function (x) {
if (x.additional) {
db.foo.update({
_id: x._id
}, {
$set: {
"name.last": x.name.additional
}, $unset: {
"name.additional": 1
}
});
}
}
db.foo.find().forEach(remap);
In MongoDB 3.2 you can also use
db.students.updateMany({}, {
$rename: {
"oldname": "newname"
}
})
The general syntax of this is
db.collection.updateMany(filter, update, options)
https://docs.mongodb.com/manual/reference/method/db.collection.updateMany/
You can use the $rename field update operator:
db.collection.update(
{},
{ $rename: { 'name.additional': 'name.last' } },
{ multi: true }
)
If ever you need to do the same thing with mongoid:
Model.all.rename(:old_field, :new_field)
UPDATE
There is change in the syntax in monogoid 4.0.0:
Model.all.rename(old_field: :new_field)
Anyone could potentially use this command to rename a field from the collection (By not using any _id):
dbName.collectionName.update({}, {$rename:{"oldFieldName":"newFieldName"}}, false, true);
see FYI
I am using ,Mongo 3.4.0
The $rename operator updates the name of a field and has the following form:
{$rename: { <field1>: <newName1>, <field2>: <newName2>, ... } }
for e.g
db.getCollection('user').update( { _id: 1 }, { $rename: { 'fname': 'FirstName', 'lname': 'LastName' } } )
The new field name must differ from the existing field name. To specify a in an embedded document, use dot notation.
This operation renames the field nmae to name for all documents in the collection:
db.getCollection('user').updateMany( {}, { $rename: { "add": "Address" } } )
db.getCollection('user').update({}, {$rename:{"name.first":"name.FirstName"}}, false, true);
In the method above false, true are: { upsert:false, multi:true }.To update all your records, You need the multi:true.
Rename a Field in an Embedded Document
db.getCollection('user').update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
use link : https://docs.mongodb.com/manual/reference/operator/update/rename/
This nodejs code just do that , as #Felix Yan mentioned former way seems to work just fine , i had some issues with other snipets hope this helps.
This will rename column "oldColumnName" to be "newColumnName" of table "documents"
var MongoClient = require('mongodb').MongoClient
, assert = require('assert');
// Connection URL
//var url = 'mongodb://localhost:27017/myproject';
var url = 'mongodb://myuser:mypwd#myserver.cloud.com:portNumber/databasename';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Connected successfully to server");
renameDBColumn(db, function() {
db.close();
});
});
//
// This function should be used for renaming a field for all documents
//
var renameDBColumn = function(db, callback) {
// Get the documents collection
console.log("renaming database column of table documents");
//use the former way:
remap = function (x) {
if (x.oldColumnName){
db.collection('documents').update({_id:x._id}, {$set:{"newColumnName":x.oldColumnName}, $unset:{"oldColumnName":1}});
}
}
db.collection('documents').find().forEach(remap);
console.log("db table documents remap successfully!");
}
If you are using MongoMapper, this works:
Access.collection.update( {}, { '$rename' => { 'location' => 'location_info' } }, :multi => true )