when i run db.abhishek.em.find({}) I have
{ "_id" : ObjectId("5ac62d35b075e574b3e7eeaa"), "name" : "first", "employed" : true }
{ "_id" : ObjectId("5ac62d3fb075e574b3e7eeab"), "name" : "second", "employed" : true }
{ "_id" : ObjectId("5ac62d4eb075e574b3e7eeac"), "name" : "third", "employed" : false }
I want to reduce this result into an array of simple object ids like this by adding or chaining something to find function , something like
db.a.b.find({employed:true}).somefunction() which can return the below array
I want to use the command nested with $in in a bigger query to achieve some sort of relational querying
[
ObjectId("5ac62d35b075e574b3e7eeaa"),
ObjectId("5ac62d3fb075e574b3e7eeab")
]
-----------------EDIT----------------------
For an example case I want to get employed employees by running
db.abhishek.another.find({id:{$in:db.abhishek.em.find({employed:true},{_id:1}).toArray()}})
or something similiar as this command is not working
The db.a.another collection is
{ "_id" : ObjectId("5ac63de1b075e574b3e7eead"), "id" : ObjectId("5ac62d35b075e574b3e7eeaa"), "name" : "Lets say person 1" }
{ "_id" : ObjectId("5ac63df7b075e574b3e7eeae"), "id" : ObjectId("5ac62d3fb075e574b3e7eeab"), "name" : "Lets say person 2" }
{ "_id" : ObjectId("5ac63e06b075e574b3e7eeaf"), "id" : ObjectId("5ac62d4eb075e574b3e7eeac"), "name" : "Lets say person 3" }
-----------------EDIT----------------------
Solved see my answer below
Use MongoDB to only provide those fields from the model. In MongoDB terms this is called Projection. There is a MongoDB method .project() that you can chain onto your query like this:
db.abhishek.em.find({}).project({});
that should do it. If you want to explicit exclude fields, you do:
db.abhishek.em.find({}).project({name:0, employed:0});
then, finally, to get the output in array form do:
db.abhishek.em.find({}).project({name:0, employed:0}).toArray();
Reference here:
https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/
Thanks everyone for providing directions and suggestions to move forward,
I was able to successfully do some sort of relational based query using the following
db.abhishek.another.find({id:{$in:db.abhishek.em.find({employed:true},{_id:1}).map(function(e) {return e._id})}},{name:1,_id:0})
It gave this as output
{ "name" : "Lets say person 1" }
{ "name" : "Lets say person 2" }
This query took all records from em collection with employed set to true,form its array and then pass it to $in operator on query for "another" collection to give output
toArray method used to convert objects nested in array hence failing $in operator
Thanks #veeram for telling about selection of fields
Related
I have this collection:
[{ "_id" : 7,
"category" : "Festival",
"comments" : [
{
"_id" : ObjectId("4da4e7d1590295d4eb81c0c7"),
"usr" : "Mila",
"txt" : "This is a comment",
"date" : "4/12/11"
}
]
}]
All I want is to push insert a new field inside comments like this:
[{ "_id" : 7,
"category" : "Festival",
"comments" : [
{
"_id" : ObjectId("4da4e7d1590295d4eb81c0c7"),
"usr" : "Mila",
"txt" : "This is a comment",
"date" : "4/12/11",
"type": "abc" // find the parent doc with id=7 & insert this inside comments
}
]
}]
How can I insert inside the comments subdocument?
You need to use the $ positional operator
For example:
update({
_id: 7,
"comments._id": ObjectId("4da4e7d1590295d4eb81c0c7")
},{
$set: {"comments.$.type": abc}
}, false, true
);
I didn't test it but i hope that it will be helpful for you.
If you want to change the structure of document you need to use
db.collection.update( criteria,
objNew, upsert, multi )
Arguments:
criteria - query which selects the record to update;
objNew - updated object or $ operators (e.g., $inc) which manipulate the object
upsert - if this should be an "upsert"; that is, if the record does not exist, nsert it
multi - if all documents matching criteria should be updated
and insert new objNew with new structure. check this for more details
The $ positional operator is only going to work as expected if the 'comments' field is NOT an array. The OP's json is malformed, but it looks like it could be an array.
The issue is that mongodb right now will only update the first element of an array which matches the query. Though there is an RFE open to add support for updating all matching array elements: https://jira.mongodb.org/browse/SERVER-1243
To work around this issue with arrays you just have to do a regular find then update the elements in the array individually.
I could create a big query, and turn it into a view. Let's call it DBA_VIEW.
db.DBA_VIEW.find()
I'm using noSQLbooster to interact with mongodb and I'm trying to insert the result of this view into another collection.
I don't want to "right click > export" because I need to do this via noSQLbooster itself.
I've seen some querie sthat can do the trick, but, as a SQL SERVER dba, I think I can't get the logic behind, let's say, this one below:
db.full_set.find({date:"20120105"}).forEach(function(doc){
db.subset.insert(doc);
});
how can I use such approach to do my taks?
I just need the result of that view from a collection, to be inserted in another collection, then after this we are going to export the data into a .json file or even a .TXT.
You can design the query in the following way so that the output is directly inserted in a new collection('subset' in this example) without iterating through the result set.
db.full_set.aggregate([
{
$match:{
"date":"20120105"
}
},
{
$out:"subset"
}
])
If 'full_set' has the following documents:
{
"_id" : ObjectId("5d423675bd542251420b6b8e"),
"date" : "20130105",
"name" : "Mechanic1"
}
{
"_id" : ObjectId("5d423675bd542251420b6b8f"),
"date" : "20120105",
"name" : "Mechanic2"
}
{
"_id" : ObjectId("5d423675bd542251420b6b90"),
"date" : "20120105",
"name" : "Mechanic3"
}
With the above query, the 'subset' collection would be having the following documents:
{
"_id" : ObjectId("5d423675bd542251420b6b8f"),
"date" : "20120105",
"name" : "Mechanic2"
}
{
"_id" : ObjectId("5d423675bd542251420b6b90"),
"date" : "20120105",
"name" : "Mechanic3"
}
I'm attempting to filter returned data sets with Meteor's find().fetch() to contain just a single object, it doesn't appear very useful if I query for a single subdocument but instead I receive several, some not even containing any of the matched terms.
I have a simple mixed data collection that looks like this:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"items" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06"),
"slug" : "this-is-a-long-slug",
"title" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6"),
"slug" : "mc",
"title" : "Technology"
}
]
}
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e8"),
"name" : "Sitewide",
"items" : [
{
"_id" : ObjectId("57a38bc75ac9e2efc0fa09c9"),
"slug" : "example",
"name" : "Single Example"
}
]
}
I can easily query for a specific object in the nested items array with the MongoDB shell as this:
db.categories.find( { "items.slug": "mc" }, { "items.$": 1 } );
This returns good data, it contains just the single object I want to work with:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"items" : [
{
"_id" : ObjectId("57a38b985ac9e2efc0fa09c8")
"slug" : "mc",
"name" : "Single Example"
}
]
}
However, if a similar query within Meteor is directly attempted:
/* server/publications.js */
Meteor.publish('categories.all', function () {
return Categories.find({}, { sort: { position: 1 } });
});
/* imports/ui/page.js */
Template.page.onCreated(function () {
this.subscribe('categories.all');
});
Template.page.helpers({
items: function () {
var item = Categories.find(
{ "items.slug": "mc" },
{ "items.$": 1 } )
.fetch();
console.log('item: %o', item);
}
});
The outcome isn't ideal as it returns the entire matched block, as well as every object in the nested items array:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"boards" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06")
"slug" : "this-is-a-long-slug",
"name" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6")
"slug" : "mc",
"name" : "Technology"
}
]
}
I can then of course filter the returned cursor even further with a for loop to get just the needed object, but this seems unscalable and terribly inefficient while dealing with larger data sets.
I can't grasp why Meteor's find returns a completely different set of data than MongoDB's shell find, the only reasonable explanation is both function signatures are different.
Should I break up my nested collections into smaller collections and take a more relational database approach (i.e. store references to ObjectIDs) and query data from collection-to-collection, or is there a more powerful means available to efficiently filter large data sets into single objects that contain just the matched objects as demonstrated above?
The client side implementation of Mongo used by Meteor is called minimongo. It currently only implements a subset of available Mongo functionality. Minimongo does not currently support $ based projections. From the Field Specifiers section of the Meteor API:
Field operators such as $ and $elemMatch are not available on the client side yet.
This is one of the reasons why you're getting different results between the client and the Mongo shell. The closest you can get with your original query is the result you'll get by changing "items.$" to "items":
Categories.find(
{ "items.slug": "mc" },
{ "items": 1 }
).fetch();
This query still isn't quite right though. Minimongo expects your second find parameter to be one of the allowed option parameters outlined in the docs. To filter fields for example, you have to do something like:
Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items": 1
}
}
).fetch();
On the client side (with Minimongo) you'll then need to filter the result further yourself.
There is another way of doing this though. If you run your Mongo query on the server, you won't be using Minimongo, which means projections are supported. As a quick example, try the following:
/server/main.js
const filteredCategories = Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items.$": 1
}
}
).fetch();
console.log(filteredCategories);
The projection will work, and the logged results will match the results you see when using the Mongo console directly. Instead of running your Categories.find on the client side, you could instead create a Meteor Method that calls your Categories.find on the server, and returns the results back to the client.
all!
I'm new to MongoDB aggregation, after aggregating, I finally get the result:
"result" : [
{
"_id" : "531d84734031c76f06b853f0"
},
{
"_id" : "5316739f4031c76f06b85399"
},
{
"_id" : "53171a7f4031c76f06b853e5"
},
{
"_id" : "531687024031c76f06b853db"
},
{
"_id" : "5321135cf5fcb31a051e911a"
},
{
"_id" : "5315b2564031c76f06b8538f"
}
],
"ok" : 1
The data is just what I'm looking for, but I just want to make it one step further, I hope my data will be displayed like this:
"result" : [
"531d84734031c76f06b853f0",
"5316739f4031c76f06b85399",
"53171a7f4031c76f06b853e5",
"531687024031c76f06b853db",
"5321135cf5fcb31a051e911a",
"5315b2564031c76f06b8538f"
],
"ok" : 1
Yes, I just want to get all the unique id in a plain string array, is there anything I could do? Any help would be appreciated!
All MongoDB queries produce "key/value" pairs in the result document. All MongoDB content is basically a BSON document in this form, which is just "translated" back to native code form by the driver to the language it is implemented in.
So the aggregation framework alone is never going to produce a bare array of just the values as you want. But you can always just transform the array of results, as after all it is only an array
var result = db.collection.aggregate(pipeline);
var response = result.result.map(function(x) { return x._id } );
Also note that the default behavior in the shell and a preferred option is that the aggregation result is actually returned as a cursor from MongoDB 2.6 and onwards. Since this is in list form rather than as a distinct document you would process differently:
var response = db.collection.aggregate(pipeline).map(function(x) {
return x._id;
})
At this moment I have in Node.JS API written a function
Board.find({ users : req.user._id})
It will find all documents where is id of user inside of array users,
for example
So this function will find this document.
{
"_id" : ObjectId("5a7f4b46f489dd236410d88a"),
"name" : "first",
"users" : [
ObjectId("5a1db9e8db97d318ac70715d")
]
}
What If I will change array of users in document for array objects id
{
"_id" : ObjectId("5a7f4b46f489dd236410d77c"),
"name" : "second",
"users" : [
{ _id : ObjectId("5a1db9e8db97d318ac70715d") }
]
}
How to find now this document in this situation, using only req.user._id which is saved inside object of users[]?
we can find it somehow now or not??
You just need to change it as : Board.find({ 'users._id' : req.user._id})
You could also use:
db.collection_name.find( { "user": { "_id" : req.user._id } } )