I have found this tutorial online which is helpful. However it shows an example using an array of two objectIds. How could the query be done if it was one objectId instead of two?
http://www.tutorialspoint.com/mongodb/mongodb_relationships.htm
{
"_id":ObjectId("52ffc33cd85242f436000001"),
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin",
"address_ids": [
ObjectId("52ffc4a5d85242602e000000"), // if this was not an array and just one ObjectId
ObjectId("52ffc4a5d85242602e000001")
]
}
var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})
var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})
I hope I got it right. So you have elements of this sort:
{
"_id":ObjectId("52ffc33cd85242f436000001"),
...
"address_ids": ObjectId("52ffc4a5d85242602e000000")
}
Your code will look like this:
var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})
var addresses = db.address.find({"_id": result["address_ids"]})
Related
In the sample_training database, companies collection, there is data like the following one:
Exercise: How many companies in the sample_training.companies collection have offices in the city of "Seattle"?
The query I thought of was with the dot notation as follows:
db.companies.find({ "offices.0.city": "Seattle" }).count()
This returns 110.
However, the site gives the following query as the correct one
db.companies.find({ "offices": { "$elemMatch": { "city": "Seattle" } } }).count()
This returns 117.
I have checked that my query seems to work fine as well, but I don't know why they differ in their result.
The difference is you are only looking at the first element (index 0) in the array. You are specifying the index to look at.
Meaning, if we have the following database:
[
{
"offices": [
{
"city": "Dallas"
},
{
"city": "Jacksonville"
}
]
}
]
With the following query:
db.collection.find({
"offices.0.city": "Jacksonville"
})
It would return nothing.
Whereas, if we used this query, the element does not have to be the first index.
db.collection.find({
"offices": {
"$elemMatch": {
"city": "Jacksonville"
}
}
})
Live Demos:
Working - https://mongoplayground.net/p/wnX-arcooa7
Not Working - https://mongoplayground.net/p/zFWV00TzZjj
I went to the wine db - https://www.pdbmbook.com/playground/mongo/wine/view/pgdb____1635519319_617c0b57588c7
And I did:
db.products.find( { "type": "rose"}).count();
Result = 3
db.products.find({ "products.0.type": "rose" }).count();
Result: 0
db.products.find({ "products": { "$elemMatch": { "type": "rose" } } }).count()
Result: 0
I suspect I get back 0 since the online playground I used is limited in functionality. Nevertheless I would assume any field that references the index of the object e.g. "offices.0.city" would mean you are starting the count higher up the tree or at 0.
I am trying to updateMany() documents which are an array of documents, if they have a certain value. I am still learning mongodb and I know how to update all documents if they have this value with my new value. The problem I think I am having is that they are an array of documents so I need to go into each document find the field called courses go inside of it and find the document called name and then update it the value of name and I have been trying, but no luck. Also In the request I update the first collection no problem its when I get into the next collection where it does nothing like I already mentioned.
request.body.code = request.sanitize(request.body.code);
request.body.name = request.sanitize(request.body.name);
request.body.courses.forEach(course => {
course.code = request.sanitize(course.code);
course.name = request.sanitize(course.name);
});
let newValues = { $set: {"code": request.body.code, "name":request.body.name } };
result = await mongoClient.db(DB_NAME).collection("all_courses").updateOne(selector, newValues);
// Okay now try to update other collection of array documents which isnt working yet
selector = { "code": "PROG2700"};
newValues = { $set: {"code": request.body.code, "name": request.body.name } };
console.log("this is new values");
console.log(request.body.courses);
result = await mongoClient.db(DB_NAME).collection("technologies").updateMany(selector,newValues);
That is in my server doing the mongodb work and trying to update the documents.
let sendString:Object = {
"id": my,
"code": edit_Course?.code,
"name": state_category_name,
"courses":
[
{
"code": edit_Course?.code,
"name": state_category_name
}
]
}
That is what I am sending to the server as the request.body
{
"_id": "5fdaa52060689aa159e4122e",
"name": "Webpack",
"description": "Webpack is great",
"difficulty": 2,
"courses": [
{
"code": "PROG2700",
"name": "Client Side Programming"
},
{
"code": "PROG3017",
"name": "Full Stack Programming"
}
]
}
That is what the mongodb structure of each document looks like in the technologies collection that I am having trouble updating. Its the name field I need to update in every document under courses. Could anyone give me a helping hand, many thanks!
Your selector filter doesn't work for the technologies class because the matching code field is part of an array named courses. To account for this, the filter should look something like this:
{ "courses.code": "PROG2700" }
This is an example of querying a field in a document embedded in an array.
The next step is to update the right document in the array. This can be done in MongoDB using the positional operator $. The update document would look like this:
{ $set: { "courses.$.code": request.body.code, "courses.$.name": request.body.name }}
In this update document, the positional operator tells MongoDB to update the code and name fields of the first document in the courses array with a code of PROG2700.
Put together, the update might look like this:
filter = { "courses.code": "PROG2700" };
update = { $set: { "courses.$.code": request.body.code, "courses.$.name": request.body.name }};
result = await mongoClient.db(DB_NAME).collection("technologies").updateMany(filter,update);
How to achieve below SQL in MongoShell?
Select TableA.* from TableA where TableA.FieldB in (select TableB.FieldValue from TableB)
Mongo doc gives some example of
db.inventory.find( { qty: { $in: [ 5, 15 ] } } )
I want that array be dynamically from another query. Is it possible?
Extending my question
I have a collection of bot names
bots collection
{
"_id" : ObjectId("53266697c294991f57c36e42"),
"name" : "teoma"
}
I have a collection of user traffic, in that traffic collection, I have a field useragent
userTraffic Collection
{
"_id" : ObjectId("5325ee6efb91c0161cbe7b2c"),
"hosttype" : "http",
"useragent" : "Mediapartners-Google",
"is_crawler" : false,
"City" : "Mountain View",
"State" : "CA",
"Country" : "United States"
}
I want to select all user traffic documents where its useragent contains any name of bot collection
This is what I have come up with
var botArray = db.bots.find({},{name:1, _id:0}).toArray()
db.Sessions.find({
useragent: {$in: botArray}
},{
ipaddress:1
})
Here i believe it is doing equals to comparison, but I want it to do like %% comparison
Once I get the result, I want to do an update to that result set as is_crawler= true
Tried something like this, isn't helpful
db.bots.find().forEach( function(myBot) {
db.Sessions.find({
useragent: /myBot.name/
},{
ipaddress:1
})
});
Another way of looping through the records, but no match found.
var bots = db.bots.find( {
$query: {},
$orderby:{
name:1}
});
while( bots.hasNext()) {
var bot = bots.next();
//print(bot.name);
var botName = bot.name.toLowerCase();
print(botName);
db.Sessions.find({
useragent: /botName/,
is_crawler:false
},{
start_date:1,
ipaddress:1,
useragent:1,
City:1,
State:1,
Country:1,
is_crawler:1,
_id:0
})
}
Not in a single query it isn't.
There is nothing wrong with getting the results from a query and feeding that in as your in condition.
var list = db.collectionA.find({},{ "_id": 0, "field": 1 }).toArray();
results = db.collectionB.find({ "newfield": { "$in": list } });
But your actual purpose is not clear, as using SQL queries alone as the only example of what you want to achieve are generally not a good guide to answer the question. The main cause of this is that you probably should be modelling differently than as you do in relational. Otherwise, why use MongoDB at all?
I would suggest reading the documentation section on Data Modelling which shows several examples of how to approach common modelling cases.
Considering that information, then perhaps you can reconsider what you are modelling, and if you then have specific questions to other problems there, then feel free to ask your questions here.
Finally this is how I could accomplish it.
// Get a array with values for name field
var botArray = db.bots.find({},{name:1}).toArray();
// loop through another collection
db.Sessions.find().forEach(function(sess){
if(sess.is_crawler == false){ // check a condition
// loop in the above array
botArray.forEach(function(b){
//check if exists in the array
if(String(sess.useragent).toUpperCase().indexOf(b.name.toUpperCase()) > -1){
db.Sessions.update({ _id : sess._id} // find by _id
,{
is_crawler : true // set a update value
},
{
upsert:false // do update only
})
}
});
}
});
I am new to MongoDB and NoSQL and have the following query:
I have the following documents in a sample MongoDB Collection
Data Collection
{ "Name" : "A",
"date" : "2015-04-29"
},
{ "Name" : "B",
"date" : "2015-04-29"
},
{ "Name" : "A",
"date" : "2015-04-30"
}
I want to run a query on the comparing the dates trying to find out which name was not present on date = "2015-04-30" but was present on date = "2015-04-29".
The result of the above query would be :
{ "Name" : "B" }
Basically trying to compare results from two mongodb queries and then showing a result.
Please let me know if this would be possible to do.
I would achieve it with sets.
First take the elements that you are interested in:
var need = db.a.distinct('Name', {date: '2015-04-29'})
take the element that you are not interested:
var doNotNeed = db.a.distinct('Name', {date: '2015-04-30'})
Now if you subtract the set(need) with set(doNotNeed), you will get your answers. Mongoshell does not support sets, but you can use dictionaries:
var needSet = {}
for (var i=0; i < need.length; i++){
needSet[need[i]] = 1;
}
for (var i=0; i < doNotNeed.length; i++){
if (doNotNeed[i] in needSet){
delete needSet[doNotNeed[i]]
}
}
needSet would have all the elements that satisfy your query. You can get them by calling Object.keys(needSet).
You can do that using aggregation pipeline operators. First you will need to group your document by Name using $group. The $push is a accumulator operator that let you create and array of date field. Use $match to field document with given criteria.
db.data.aggregate(
[
{ "$group": { "_id": "$Name", "date": { "$push": "$date" }}},
{ "$match": { "date": { "$not": { "$all": ["2015-04-29", "2015-04-30" ]}}}},
]
)
I had similar issue, try this snippet
var arr=[];
db.Collection.find({"date":"2015-04-30"}).forEach(function(item){
var val=item.Name;
var found=db.Collection.findOne({"date":"2015-04-29","Name":val});
if (!found)
arr.push(val);
});
printjson(arr);
How to achieve below SQL in MongoShell?
Select TableA.* from TableA where TableA.FieldB in (select TableB.FieldValue from TableB)
Mongo doc gives some example of
db.inventory.find( { qty: { $in: [ 5, 15 ] } } )
I want that array be dynamically from another query. Is it possible?
Extending my question
I have a collection of bot names
bots collection
{
"_id" : ObjectId("53266697c294991f57c36e42"),
"name" : "teoma"
}
I have a collection of user traffic, in that traffic collection, I have a field useragent
userTraffic Collection
{
"_id" : ObjectId("5325ee6efb91c0161cbe7b2c"),
"hosttype" : "http",
"useragent" : "Mediapartners-Google",
"is_crawler" : false,
"City" : "Mountain View",
"State" : "CA",
"Country" : "United States"
}
I want to select all user traffic documents where its useragent contains any name of bot collection
This is what I have come up with
var botArray = db.bots.find({},{name:1, _id:0}).toArray()
db.Sessions.find({
useragent: {$in: botArray}
},{
ipaddress:1
})
Here i believe it is doing equals to comparison, but I want it to do like %% comparison
Once I get the result, I want to do an update to that result set as is_crawler= true
Tried something like this, isn't helpful
db.bots.find().forEach( function(myBot) {
db.Sessions.find({
useragent: /myBot.name/
},{
ipaddress:1
})
});
Another way of looping through the records, but no match found.
var bots = db.bots.find( {
$query: {},
$orderby:{
name:1}
});
while( bots.hasNext()) {
var bot = bots.next();
//print(bot.name);
var botName = bot.name.toLowerCase();
print(botName);
db.Sessions.find({
useragent: /botName/,
is_crawler:false
},{
start_date:1,
ipaddress:1,
useragent:1,
City:1,
State:1,
Country:1,
is_crawler:1,
_id:0
})
}
Not in a single query it isn't.
There is nothing wrong with getting the results from a query and feeding that in as your in condition.
var list = db.collectionA.find({},{ "_id": 0, "field": 1 }).toArray();
results = db.collectionB.find({ "newfield": { "$in": list } });
But your actual purpose is not clear, as using SQL queries alone as the only example of what you want to achieve are generally not a good guide to answer the question. The main cause of this is that you probably should be modelling differently than as you do in relational. Otherwise, why use MongoDB at all?
I would suggest reading the documentation section on Data Modelling which shows several examples of how to approach common modelling cases.
Considering that information, then perhaps you can reconsider what you are modelling, and if you then have specific questions to other problems there, then feel free to ask your questions here.
Finally this is how I could accomplish it.
// Get a array with values for name field
var botArray = db.bots.find({},{name:1}).toArray();
// loop through another collection
db.Sessions.find().forEach(function(sess){
if(sess.is_crawler == false){ // check a condition
// loop in the above array
botArray.forEach(function(b){
//check if exists in the array
if(String(sess.useragent).toUpperCase().indexOf(b.name.toUpperCase()) > -1){
db.Sessions.update({ _id : sess._id} // find by _id
,{
is_crawler : true // set a update value
},
{
upsert:false // do update only
})
}
});
}
});