Câu trả lời:
Bạn có thể làm điều này với MapReduce:
mr = db.runCommand({
"mapreduce" : "my_collection",
"map" : function() {
for (var key in this) { emit(key, null); }
},
"reduce" : function(key, stuff) { return null; },
"out": "my_collection" + "_keys"
})
Sau đó chạy riêng biệt trên bộ sưu tập kết quả để tìm tất cả các khóa:
db[mr.result].distinct("_id")
["foo", "bar", "baz", "_id", ...]
for (var key in this.first_level.second_level.nth_level) { emit(key, null); }
db.runCommand({..., out: { "inline" : 1 }}).results.map(function(i) { return i._id; });
Với câu trả lời của Kristina là nguồn cảm hứng, tôi đã tạo ra một công cụ nguồn mở có tên Variety, chính xác là thế này: https://github.com/variety/variety
Bạn có thể sử dụng kết hợp với mới $objectToArrray
trong 3.4.4
phiên bản để chuyển đổi tất cả các chìa khóa top & cặp giá trị vào mảng tài liệu tiếp theo $unwind
& $group
có $addToSet
để có được chìa khóa riêng biệt trên toàn bộ bộ sưu tập.
$$ROOT
để tham khảo tài liệu cấp cao nhất.
db.things.aggregate([
{"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
{"$unwind":"$arrayofkeyvalue"},
{"$group":{"_id":null,"allkeys":{"$addToSet":"$arrayofkeyvalue.k"}}}
])
Bạn có thể sử dụng truy vấn dưới đây để nhận khóa trong một tài liệu.
db.things.aggregate([
{"$match":{_id: "5e8f968639bb8c67726686bc"}}, /* Replace with the document's ID */
{"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
{"$project":{"keys":"$arrayofkeyvalue.k"}}
])
.next()["allkeys"]
lệnh (giả sử bộ sưu tập có ít nhất một phần tử).
Thử cái này:
doc=db.thinks.findOne();
for (key in doc) print(key);
Nếu bộ sưu tập mục tiêu của bạn không quá lớn, bạn có thể thử điều này trong ứng dụng khách mongo shell:
var allKeys = {};
db.YOURCOLLECTION.find().forEach(function(doc){Object.keys(doc).forEach(function(key){allKeys[key]=1})});
allKeys;
Một giải pháp làm sạch và tái sử dụng bằng pymongo:
from pymongo import MongoClient
from bson import Code
def get_keys(db, collection):
client = MongoClient()
db = client[db]
map = Code("function() { for (var key in this) { emit(key, null); } }")
reduce = Code("function(key, stuff) { return null; }")
result = db[collection].map_reduce(map, reduce, "myresults")
return result.distinct('_id')
Sử dụng:
get_keys('dbname', 'collection')
>> ['key1', 'key2', ... ]
if (typeof(this[key]) == 'number')
trước emit(key, null)
.
Sử dụng trăn. Trả về tập hợp tất cả các khóa cấp cao nhất trong bộ sưu tập:
#Using pymongo and connection named 'db'
reduce(
lambda all_keys, rec_keys: all_keys | set(rec_keys),
map(lambda d: d.keys(), db.things.find()),
set()
)
Đây là mẫu làm việc trong Python: Mẫu này trả về kết quả nội tuyến.
from pymongo import MongoClient
from bson.code import Code
mapper = Code("""
function() {
for (var key in this) { emit(key, null); }
}
""")
reducer = Code("""
function(key, stuff) { return null; }
""")
distinctThingFields = db.things.map_reduce(mapper, reducer
, out = {'inline' : 1}
, full_response = True)
## do something with distinctThingFields['results']
Nếu bạn đang sử dụng mongodb 3.4.4 trở lên thì bạn có thể sử dụng tổng hợp bên dưới bằng cách sử dụng $objectToArray
và $group
tổng hợp
db.collection.aggregate([
{ "$project": {
"data": { "$objectToArray": "$$ROOT" }
}},
{ "$project": { "data": "$data.k" }},
{ "$unwind": "$data" },
{ "$group": {
"_id": null,
"keys": { "$addToSet": "$data" }
}}
])
Dưới đây là ví dụ làm việc
$match
ở đầu đường ống tổng hợp để chỉ lấy các khóa của tài liệu khớp với (các) điều kiện.
Tôi ngạc nhiên, không ai ở đây có ans bằng cách sử dụng đơn giản javascript
và Set
logic để tự động lọc các giá trị trùng lặp, ví dụ đơn giản trên vỏ mongo như dưới đây:
var allKeys = new Set()
db.collectionName.find().forEach( function (o) {for (key in o ) allKeys.add(key)})
for(let key of allKeys) print(key)
Điều này sẽ in tất cả các khóa duy nhất có thể có trong tên bộ sưu tập : CollectionName .
Tôi nghĩ rằng cách tốt nhất để làm điều này như được đề cập ở đây là trong mongod 3.4.4+ nhưng không sử dụng $unwind
toán tử và chỉ sử dụng hai giai đoạn trong đường ống. Thay vào đó chúng ta có thể sử dụng $mergeObjects
và các $objectToArray
toán tử.
Trong $group
giai đoạn, chúng tôi sử dụng $mergeObjects
toán tử để trả về một tài liệu duy nhất trong đó khóa / giá trị là từ tất cả các tài liệu trong bộ sưu tập.
Sau đó đến $project
nơi chúng tôi sử dụng $map
và $objectToArray
trả lại các phím.
let allTopLevelKeys = [
{
"$group": {
"_id": null,
"array": {
"$mergeObjects": "$$ROOT"
}
}
},
{
"$project": {
"keys": {
"$map": {
"input": { "$objectToArray": "$array" },
"in": "$$this.k"
}
}
}
}
];
Bây giờ nếu chúng ta có một tài liệu lồng nhau và muốn lấy các khóa là tốt, điều này là có thể làm được. Để đơn giản, hãy xem xét một tài liệu với tài liệu nhúng đơn giản trông như thế này:
{field1: {field2: "abc"}, field3: "def"}
{field1: {field3: "abc"}, field4: "def"}
Các đường ống sau đây mang lại tất cả các khóa (trường1, trường2, trường3, trường4).
let allFistSecondLevelKeys = [
{
"$group": {
"_id": null,
"array": {
"$mergeObjects": "$$ROOT"
}
}
},
{
"$project": {
"keys": {
"$setUnion": [
{
"$map": {
"input": {
"$reduce": {
"input": {
"$map": {
"input": {
"$objectToArray": "$array"
},
"in": {
"$cond": [
{
"$eq": [
{
"$type": "$$this.v"
},
"object"
]
},
{
"$objectToArray": "$$this.v"
},
[
"$$this"
]
]
}
}
},
"initialValue": [
],
"in": {
"$concatArrays": [
"$$this",
"$$value"
]
}
}
},
"in": "$$this.k"
}
}
]
}
}
}
]
Với một chút nỗ lực, chúng ta có thể nhận được khóa cho tất cả các văn bản con trong trường mảng trong đó các phần tử cũng là đối tượng.
$unwind
sẽ làm nổ bộ sưu tập (các trường no.of * no.of doc), chúng ta có thể tránh điều đó bằng cách sử dụng $mergeObjects
trên tất cả các phiên bản> 3.6
.. Đã làm như vậy, nên đã thấy câu trả lời này trước đây, cuộc sống của tôi sẽ dễ dàng hơn theo cách đó ( -_-)
Có thể hơi lạc đề, nhưng bạn có thể in đệ quy tất cả các khóa / trường của một đối tượng:
function _printFields(item, level) {
if ((typeof item) != "object") {
return
}
for (var index in item) {
print(" ".repeat(level * 4) + index)
if ((typeof item[index]) == "object") {
_printFields(item[index], level + 1)
}
}
}
function printFields(item) {
_printFields(item, 0)
}
Hữu ích khi tất cả các đối tượng trong một bộ sưu tập có cùng cấu trúc.
Để có được danh sách tất cả các phím trừ _id
, hãy xem xét chạy đường ống tổng hợp sau:
var keys = db.collection.aggregate([
{ "$project": {
"hashmaps": { "$objectToArray": "$$ROOT" }
} },
{ "$project": {
"fields": "$hashmaps.k"
} },
{ "$group": {
"_id": null,
"fields": { "$addToSet": "$fields" }
} },
{ "$project": {
"keys": {
"$setDifference": [
{
"$reduce": {
"input": "$fields",
"initialValue": [],
"in": { "$setUnion" : ["$$value", "$$this"] }
}
},
["_id"]
]
}
}
}
]).toArray()[0]["keys"];
Tôi đã cố gắng viết trong nodejs và cuối cùng đã nghĩ ra điều này:
db.collection('collectionName').mapReduce(
function() {
for (var key in this) {
emit(key, null);
}
},
function(key, stuff) {
return null;
}, {
"out": "allFieldNames"
},
function(err, results) {
var fields = db.collection('allFieldNames').distinct('_id');
fields
.then(function(data) {
var finalData = {
"status": "success",
"fields": data
};
res.send(finalData);
delteCollection(db, 'allFieldNames');
})
.catch(function(err) {
res.send(err);
delteCollection(db, 'allFieldNames');
});
});
Sau khi đọc bộ sưu tập mới được tạo "allFieldNames", hãy xóa nó.
db.collection("allFieldNames").remove({}, function (err,result) {
db.close();
return;
});
Theo tài liệu mongoldb , một sự kết hợp củadistinct
Tìm các giá trị riêng biệt cho một trường được chỉ định trong một bộ sưu tập hoặc chế độ xem và trả về kết quả trong một mảng.
và các hoạt động thu thập chỉ mục là những gì sẽ trả về tất cả các giá trị có thể cho một khóa hoặc chỉ mục đã cho:
Trả về một mảng chứa danh sách các tài liệu xác định và mô tả các chỉ mục hiện có trên bộ sưu tập
Vì vậy, trong một phương thức đã cho, người ta có thể sử dụng một phương thức như phương pháp sau, để truy vấn một bộ sưu tập cho tất cả các chỉ mục đã đăng ký và trả về, nói một đối tượng có các chỉ mục cho các khóa (ví dụ này sử dụng async / await cho NodeJS, nhưng rõ ràng bạn có thể sử dụng bất kỳ phương pháp không đồng bộ nào khác):
async function GetFor(collection, index) {
let currentIndexes;
let indexNames = [];
let final = {};
let vals = [];
try {
currentIndexes = await collection.indexes();
await ParseIndexes();
//Check if a specific index was queried, otherwise, iterate for all existing indexes
if (index && typeof index === "string") return await ParseFor(index, indexNames);
await ParseDoc(indexNames);
await Promise.all(vals);
return final;
} catch (e) {
throw e;
}
function ParseIndexes() {
return new Promise(function (result) {
let err;
for (let ind in currentIndexes) {
let index = currentIndexes[ind];
if (!index) {
err = "No Key For Index "+index; break;
}
let Name = Object.keys(index.key);
if (Name.length === 0) {
err = "No Name For Index"; break;
}
indexNames.push(Name[0]);
}
return result(err ? Promise.reject(err) : Promise.resolve());
})
}
async function ParseFor(index, inDoc) {
if (inDoc.indexOf(index) === -1) throw "No Such Index In Collection";
try {
await DistinctFor(index);
return final;
} catch (e) {
throw e
}
}
function ParseDoc(doc) {
return new Promise(function (result) {
let err;
for (let index in doc) {
let key = doc[index];
if (!key) {
err = "No Key For Index "+index; break;
}
vals.push(new Promise(function (pushed) {
DistinctFor(key)
.then(pushed)
.catch(function (err) {
return pushed(Promise.resolve());
})
}))
}
return result(err ? Promise.reject(err) : Promise.resolve());
})
}
async function DistinctFor(key) {
if (!key) throw "Key Is Undefined";
try {
final[key] = await collection.distinct(key);
} catch (e) {
final[key] = 'failed';
throw e;
}
}
}
Vì vậy, truy vấn một bộ sưu tập với _id
chỉ mục cơ bản , sẽ trả về các mục sau (bộ sưu tập kiểm tra chỉ có một tài liệu tại thời điểm kiểm tra):
Mongo.MongoClient.connect(url, function (err, client) {
assert.equal(null, err);
let collection = client.db('my db').collection('the targeted collection');
GetFor(collection, '_id')
.then(function () {
//returns
// { _id: [ 5ae901e77e322342de1fb701 ] }
})
.catch(function (err) {
//manage your error..
})
});
Xin lưu ý bạn, điều này sử dụng các phương thức có nguồn gốc từ Trình điều khiển NodeJS. Như một số câu trả lời khác đã đề xuất, có những cách tiếp cận khác, chẳng hạn như khung tổng hợp. Cá nhân tôi thấy cách tiếp cận này linh hoạt hơn, vì bạn có thể dễ dàng tạo và tinh chỉnh cách trả về kết quả. Rõ ràng, điều này chỉ giải quyết các thuộc tính cấp cao nhất, không phải các thuộc tính lồng nhau. Ngoài ra, để đảm bảo rằng tất cả các tài liệu được trình bày nên có các chỉ mục phụ (không phải là chính _id), các chỉ mục đó phải được đặt thành required
.
Chúng ta có thể đạt được điều này bằng cách sử dụng tập tin mongo js. Thêm mã dưới đây vào tệp getCollectionName.js của bạn và chạy tệp js trong bảng điều khiển của Linux như được đưa ra dưới đây:
mongo --host 192.168.1.135 getCollectionName.js
db_set = connect("192.168.1.135:27017/database_set_name"); // for Local testing
// db_set.auth("username_of_db", "password_of_db"); // if required
db_set.getMongo().setSlaveOk();
var collectionArray = db_set.getCollectionNames();
collectionArray.forEach(function(collectionName){
if ( collectionName == 'system.indexes' || collectionName == 'system.profile' || collectionName == 'system.users' ) {
return;
}
print("\nCollection Name = "+collectionName);
print("All Fields :\n");
var arrayOfFieldNames = [];
var items = db_set[collectionName].find();
// var items = db_set[collectionName].find().sort({'_id':-1}).limit(100); // if you want fast & scan only last 100 records of each collection
while(items.hasNext()) {
var item = items.next();
for(var index in item) {
arrayOfFieldNames[index] = index;
}
}
for (var index in arrayOfFieldNames) {
print(index);
}
});
quit();
Cảm ơn @ackuser
Theo chủ đề từ câu trả lời của @James Cropcho, tôi đã tìm ra những điều sau đây mà tôi thấy là siêu dễ sử dụng. Nó là một công cụ nhị phân, chính xác là thứ tôi đang tìm kiếm: mongoeye .
Sử dụng công cụ này mất khoảng 2 phút để lược đồ của tôi được xuất từ dòng lệnh.
Tôi biết câu hỏi này đã 10 tuổi nhưng không có giải pháp C # và điều này khiến tôi mất hàng giờ để tìm ra. Tôi đang sử dụng trình điều khiển .NET và System.Linq
để trả về danh sách các khóa.
var map = new BsonJavaScript("function() { for (var key in this) { emit(key, null); } }");
var reduce = new BsonJavaScript("function(key, stuff) { return null; }");
var options = new MapReduceOptions<BsonDocument, BsonDocument>();
var result = await collection.MapReduceAsync(map, reduce, options);
var list = result.ToEnumerable().Select(item => item["_id"].ToString());
Tôi đã mở rộng giải pháp của Carlos LM một chút để nó chi tiết hơn.
Ví dụ về lược đồ:
var schema = {
_id: 123,
id: 12,
t: 'title',
p: 4.5,
ls: [{
l: 'lemma',
p: {
pp: 8.9
}
},
{
l: 'lemma2',
p: {
pp: 8.3
}
}
]
};
Nhập vào bảng điều khiển:
var schemafy = function(schema, i, limit) {
var i = (typeof i !== 'undefined') ? i : 1;
var limit = (typeof limit !== 'undefined') ? limit : false;
var type = '';
var array = false;
for (key in schema) {
type = typeof schema[key];
array = (schema[key] instanceof Array) ? true : false;
if (type === 'object') {
print(Array(i).join(' ') + key+' <'+((array) ? 'array' : type)+'>:');
schemafy(schema[key], i+1, array);
} else {
print(Array(i).join(' ') + key+' <'+type+'>');
}
if (limit) {
break;
}
}
}
Chạy:
schemafy(db.collection.findOne());
Đầu ra
_id <number>
id <number>
t <string>
p <number>
ls <object>:
0 <object>:
l <string>
p <object>:
pp <number>
Tôi có 1 công việc đơn giản hơn ...
Những gì bạn có thể làm là trong khi chèn dữ liệu / tài liệu vào bộ sưu tập chính của mình, "những thứ" bạn phải chèn các thuộc tính trong 1 bộ sưu tập riêng biệt, hãy nói "Things_attribut".
do đó, mỗi khi bạn chèn vào "thứ", bạn sẽ nhận được từ "Things_attribut" so sánh các giá trị của tài liệu đó với các khóa tài liệu mới của bạn nếu có bất kỳ khóa mới nào xuất hiện trong tài liệu đó và chèn lại nó.
Vì vậy, Things_attribut sẽ chỉ có 1 tài liệu về các khóa duy nhất mà bạn có thể dễ dàng nhận được khi bạn yêu cầu bằng cách sử dụng findOne ()